From 697b5b5c7d2b1c46387061fcbed24cbee51d98ce Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Wed, 4 Aug 2010 16:47:43 +0200 Subject: Introduce tapping Simplify some common parts of the recognizer code and add tapping to the gesture suite. Signed-off-by: Henrik Rydberg --- src/Makefile.am | 5 +- src/gestures-combo.c | 66 ++++++++++--------------- src/gestures-pan.c | 65 +++++++++++++++++++++++++ src/gestures-pinch.c | 63 ++++++++++++++++++++++++ src/gestures-rotate.c | 52 +++++++++----------- src/gestures-scroll.c | 74 ---------------------------- src/gestures-tapping.c | 96 +++++++++++++++++++++++++++++++++++++ src/gestures-zoom.c | 71 --------------------------- src/grail-gestures.c | 128 ++++++++++++++++++++++++++++++++----------------- src/grail-gestures.h | 68 +++++++++++--------------- src/grail-inserter.c | 107 ++++++++++++++++++++++++++++------------- src/grail-inserter.h | 27 ++++------- src/grail-recognizer.c | 29 ++--------- src/grail-recognizer.h | 7 +-- 14 files changed, 480 insertions(+), 378 deletions(-) create mode 100644 src/gestures-pan.c create mode 100644 src/gestures-pinch.c delete mode 100644 src/gestures-scroll.c create mode 100644 src/gestures-tapping.c delete mode 100644 src/gestures-zoom.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index d0a7d26..53b4300 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,10 +10,11 @@ libgrail_la_SOURCES = \ grail-bits.c \ grail-inserter.c \ grail-gestures.c \ - gestures-scroll.c \ - gestures-zoom.c \ + gestures-pan.c \ + gestures-pinch.c \ gestures-rotate.c \ gestures-combo.c \ + gestures-tapping.c \ grail-recognizer.c \ grail-api.c diff --git a/src/gestures-combo.c b/src/gestures-combo.c index 4ecd1e4..82e7b42 100644 --- a/src/gestures-combo.c +++ b/src/gestures-combo.c @@ -26,57 +26,43 @@ #include #include -void gru_reset_combo(struct grail *ge, - const struct touch_frame *frame) -{ - struct gesture_inserter *gin = ge->gin; - struct gesture_recognizer *gru = ge->gru; - struct combo_model *state = &gru->combo; - struct move_model *move = &gru->move; - gin_gesture_discard_type(gin, GRAIL_TYPE_SZRCOMBO); - state->r = move->r; - state->active = 0; - state->running = 0; -} - int gru_combo(struct grail *ge, const struct touch_frame *frame) { - struct gesture_inserter *gin = ge->gin; struct gesture_recognizer *gru = ge->gru; struct combo_model *state = &gru->combo; struct move_model *move = &gru->move; grail_prop_t prop[DIM_GRAIL_PROP]; - float dx, dy, dr, da; - int i; - dx = move->x - state->x; - dy = move->y - state->y; - dr = move->r - state->r; - da = move->a - state->a; - if (fabs(dx) < 1 && fabs(dy) < 1 && fabs(da) < 1 && fabs(dr) < 1) + if (!move->motion) { + if (state->active) { + gru_end(ge, state->gid, move); + state->active = 0; + } + return 0; + } + if (!move->x.tickle && !move->y.tickle && + !move->r.tickle && !move->a.tickle) return 0; if (!state->active) { - i = gin_gesture_begin(ge, - GRAIL_TYPE_SZRCOMBO, 2, - frame->touches, sizeof(frame->touches)); - state->geslot = i; + switch(move->ntouch) { + case 2: + state->gid = gin_gid_begin(ge, GRAIL_TYPE_COMBO2, frame); + break; + case 3: + state->gid = gin_gid_begin(ge, GRAIL_TYPE_COMBO3, frame); + break; + default: + return 0; + } state->active = 1; } - if (!state->running && - fabs(dx) < move->xbar && fabs(dy) < move->ybar && - fabs(da) < move->abar && fabs(dr) < move->rbar) + if (!move->x.active && !move->y.active && + !move->r.active && !move->a.active) return 0; - state->running = 1; - prop[0] = dx; - prop[1] = dy; - prop[2] = dr; - prop[3] = da; - gin_gesture_event(gin, state->geslot, - move->x, move->y, move->ntouch, - prop, 4); - state->x = move->x; - state->y = move->y; - state->r = move->r; - state->a = move->a; + prop[0] = move->x.active ? move->x.delta : 0; + prop[1] = move->y.active ? move->y.delta : 0; + prop[2] = move->r.active ? move->r.delta : 0; + prop[3] = move->a.active ? move->a.delta : 0; + gru_event(ge, state->gid, move, prop, 4); return 1; } diff --git a/src/gestures-pan.c b/src/gestures-pan.c new file mode 100644 index 0000000..541c502 --- /dev/null +++ b/src/gestures-pan.c @@ -0,0 +1,65 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-recognizer.h" +#include +#include + +int gru_pan(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_recognizer *gru = ge->gru; + struct combo_model *state = &gru->pan; + struct move_model *move = &gru->move; + grail_prop_t prop[DIM_GRAIL_PROP]; + if (!move->motion) { + if (state->active) { + gru_end(ge, state->gid, move); + state->active = 0; + } + return 0; + } + if (!move->x.tickle && !move->y.tickle) + return 0; + if (!state->active) { + switch(move->ntouch) { + case 2: + state->gid = gin_gid_begin(ge, GRAIL_TYPE_PAN, frame); + break; + case 3: + state->gid = gin_gid_begin(ge, GRAIL_TYPE_SWIPE, frame); + break; + default: + return 0; + } + state->active = 1; + } + if (!move->x.active && !move->y.active) + return 0; + prop[0] = move->x.active ? move->x.delta : 0; + prop[1] = move->y.active ? move->y.delta : 0; + gru_event(ge, state->gid, move, prop, 2); + return 1; +} + diff --git a/src/gestures-pinch.c b/src/gestures-pinch.c new file mode 100644 index 0000000..48e72bd --- /dev/null +++ b/src/gestures-pinch.c @@ -0,0 +1,63 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-recognizer.h" +#include +#include + +int gru_pinch(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_recognizer *gru = ge->gru; + struct combo_model *state = &gru->pinch; + struct move_model *move = &gru->move; + grail_prop_t prop[DIM_GRAIL_PROP]; + if (!move->motion) { + if (state->active) { + gru_end(ge, state->gid, move); + state->active = 0; + } + return 0; + } + if (!move->r.tickle) + return 0; + if (!state->active) { + switch(move->ntouch) { + case 2: + state->gid = gin_gid_begin(ge, GRAIL_TYPE_PINCH, frame); + break; + case 3: + state->gid = gin_gid_begin(ge, GRAIL_TYPE_SCALE, frame); + break; + default: + return 0; + } + state->active = 1; + } + if (!move->r.active) + return 0; + prop[0] = move->r.delta; + gru_event(ge, state->gid, move, prop, 1); + return 1; +} diff --git a/src/gestures-rotate.c b/src/gestures-rotate.c index 6097347..011e9a0 100644 --- a/src/gestures-rotate.c +++ b/src/gestures-rotate.c @@ -26,46 +26,38 @@ #include #include -void gru_reset_rotate(struct grail *ge, - const struct touch_frame *frame) -{ - struct gesture_inserter *gin = ge->gin; - struct gesture_recognizer *gru = ge->gru; - struct rotate_model *state = &gru->rotate; - struct move_model *move = &gru->move; - gin_gesture_discard_type(gin, GRAIL_TYPE_ROTATE); - state->a = move->a; - state->active = 0; - state->rotating = 0; -} - int gru_rotate(struct grail *ge, const struct touch_frame *frame) { - struct gesture_inserter *gin = ge->gin; struct gesture_recognizer *gru = ge->gru; - struct rotate_model *state = &gru->rotate; + struct combo_model *state = &gru->rotate; struct move_model *move = &gru->move; grail_prop_t prop[DIM_GRAIL_PROP]; - float da; - int i; - da = move->a - state->a; - if (fabs(da) < 1) + if (!move->motion) { + if (state->active) { + gru_end(ge, state->gid, move); + state->active = 0; + } + return 0; + } + if (!move->a.tickle) return 0; if (!state->active) { - i = gin_gesture_begin(ge, - GRAIL_TYPE_ROTATE, 1, - frame->touches, sizeof(frame->touches)); - state->geslot = i; + switch(move->ntouch) { + case 2: + state->gid = gin_gid_begin(ge, GRAIL_TYPE_ROTATE, frame); + break; + case 3: + state->gid = gin_gid_begin(ge, GRAIL_TYPE_TURN, frame); + break; + default: + return 0; + } state->active = 1; } - if (!state->rotating && fabs(da) < move->abar) + if (!move->a.active) return 0; - state->rotating = 1; - prop[0] = da; - gin_gesture_event(gin, state->geslot, - move->x, move->y, move->ntouch, - prop, 1); - state->a = move->a; + prop[0] = move->a.delta; + gru_event(ge, state->gid, move, prop, 1); return 1; } diff --git a/src/gestures-scroll.c b/src/gestures-scroll.c deleted file mode 100644 index 96e153b..0000000 --- a/src/gestures-scroll.c +++ /dev/null @@ -1,74 +0,0 @@ -/***************************************************************************** - * - * grail - Gesture Recognition And Instantiation Library - * - * Copyright (C) 2010 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - * Authors: - * Henrik Rydberg - * - ****************************************************************************/ - -#include "grail-recognizer.h" -#include - -void gru_reset_scroll(struct grail *ge, - const struct touch_frame *frame) -{ - struct gesture_inserter *gin = ge->gin; - struct gesture_recognizer *gru = ge->gru; - struct scroll_model *state = &gru->scroll; - struct move_model *move = &gru->move; - gin_gesture_discard_type(gin, GRAIL_TYPE_SCROLL); - state->x = move->x; - state->y = move->y; - state->active = 0; - state->moving = 0; -} - -int gru_scroll(struct grail *ge, - const struct touch_frame *frame) -{ - struct gesture_inserter *gin = ge->gin; - struct gesture_recognizer *gru = ge->gru; - struct scroll_model *state = &gru->scroll; - struct move_model *move = &gru->move; - grail_prop_t prop[DIM_GRAIL_PROP]; - float dx, dy; - int i; - dx = move->x - state->x; - dy = move->y - state->y; - if (fabs(dx) < 1 && fabs(dy) < 1) - return 0; - if (!state->active) { - i = gin_gesture_begin(ge, GRAIL_TYPE_SCROLL, 1, - frame->touches, sizeof(frame->touches)); - state->geslot = i; - state->active = 1; - } - if (!state->moving && fabs(dx) < move->xbar && fabs(dy) < move->ybar) - return 0; - state->moving = 1; - prop[0] = dx; - prop[1] = dy; - gin_gesture_event(gin, state->geslot, - move->x, move->y, move->ntouch, - prop, 2); - state->x = move->x; - state->y = move->y; - return 1; -} - diff --git a/src/gestures-tapping.c b/src/gestures-tapping.c new file mode 100644 index 0000000..453f77c --- /dev/null +++ b/src/gestures-tapping.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * + * grail - Gesture Recognition And Instantiation Library + * + * Copyright (C) 2010 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + * Authors: + * Henrik Rydberg + * + ****************************************************************************/ + +#include "grail-recognizer.h" +#include + +static const int TAP_INIT = 0; +static const int TAP_BEGIN = 1; +static const int TAP_END = 2; +static const int TAP_CANCEL = 3; + +static const int TAP_MIN_GAP_MS = 25; +static const int TAP_MAX_GAP_MS = 400; + +int gru_tapping(struct grail *ge, + const struct touch_frame *frame) +{ + struct gesture_recognizer *gru = ge->gru; + struct tapping_model *state = &gru->tapping; + struct move_model *move = &gru->move; + grail_prop_t prop[DIM_GRAIL_PROP]; + if (state->status == TAP_CANCEL) { + if (move->ntouch) + return 0; + else + state->status = TAP_INIT; + } + if (move->ntouch > state->ntouch) { + if (!state->ntouch) { + state->start = frame->time; + state->status = TAP_BEGIN; + } + state->ntouch = move->ntouch; + } else if (move->ntouch < state->ntouch) { + if (!move->ntouch) + state->status = TAP_END; + } + if (state->status == TAP_INIT) + return 0; + if (state->ntouch < 1 || state->ntouch > 5) { + state->status = TAP_CANCEL; + } + if (frame->time - state->start > TAP_MAX_GAP_MS) { + state->status = TAP_CANCEL; + } + if (state->status == TAP_END && + frame->time - state->start < TAP_MIN_GAP_MS) { + state->status = TAP_CANCEL; + } + if (state->status == TAP_CANCEL) { + if (state->active) { + gru_end(ge, state->gid, move); + state->active = 0; + } + state->ntouch = 0; + return 0; + } + if (frame->time - state->start < TAP_MIN_GAP_MS) + return 0; + if (!state->active) { + int type = GRAIL_TYPE_TAP1 + state->ntouch - 1; + state->gid = gin_gid_begin(ge, type, frame); + state->active = 1; + } + if (state->status != TAP_END) + return 0; + prop[0] = frame->time - state->start; + gin_gid_event(ge, state->gid, + move->x.val, move->y.val, state->ntouch, + prop, 1, GRAIL_STATUS_END); + state->status = TAP_INIT; + state->ntouch = 0; + state->active = 0; + return 1; +} diff --git a/src/gestures-zoom.c b/src/gestures-zoom.c deleted file mode 100644 index 9e05b8b..0000000 --- a/src/gestures-zoom.c +++ /dev/null @@ -1,71 +0,0 @@ -/***************************************************************************** - * - * grail - Gesture Recognition And Instantiation Library - * - * Copyright (C) 2010 Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - * - * Authors: - * Henrik Rydberg - * - ****************************************************************************/ - -#include "grail-recognizer.h" -#include -#include - -void gru_reset_zoom(struct grail *ge, - const struct touch_frame *frame) -{ - struct gesture_inserter *gin = ge->gin; - struct gesture_recognizer *gru = ge->gru; - struct zoom_model *state = &gru->zoom; - struct move_model *move = &gru->move; - gin_gesture_discard_type(gin, GRAIL_TYPE_ZOOM); - state->r = move->r; - state->active = 0; - state->zooming = 0; -} - -int gru_zoom(struct grail *ge, - const struct touch_frame *frame) -{ - struct gesture_inserter *gin = ge->gin; - struct gesture_recognizer *gru = ge->gru; - struct zoom_model *state = &gru->zoom; - struct move_model *move = &gru->move; - grail_prop_t prop[DIM_GRAIL_PROP]; - float dr; - int i; - dr = move->r - state->r; - if (fabs(dr) < 1) - return 0; - if (!state->active) { - i = gin_gesture_begin(ge, - GRAIL_TYPE_ZOOM, 1, - frame->touches, sizeof(frame->touches)); - state->geslot = i; - state->active = 1; - } - if (!state->zooming && fabs(dr) < move->rbar) - return 0; - state->zooming = 1; - prop[0] = dr; - gin_gesture_event(gin, state->geslot, - move->x, move->y, move->ntouch, - prop, 1); - state->r = move->r; - return 1; -} diff --git a/src/grail-gestures.c b/src/grail-gestures.c index d79da96..27f160b 100644 --- a/src/grail-gestures.c +++ b/src/grail-gestures.c @@ -25,12 +25,12 @@ #include "grail-recognizer.h" #include -static const float SN_MOVE = 50; -static const float SN_ZOOM = 50; +static const float SN_MOVE = 200; +static const float SN_ZOOM = 200; static const float SN_ROTATE = 200; -static const float BAR_MOVE = 1; -static const float BAR_ZOOM = 2; -static const float BAR_ROTATE = 4; +static const float BAR_MOVE = 4; +static const float BAR_ZOOM = 12; +static const float BAR_ROTATE = 12; static void compute_position(float *x, float *y, const struct touch_frame *frame) @@ -89,15 +89,34 @@ static float compute_rotation(float x, float y, float r, return da; } -static float move_filter(float x, float x0, float fuzz) +static float move_filter(const struct filter_model *m, float val) { - if (x > x0 - fuzz / 2 && x < x0 + fuzz / 2) - return x0; - if (x > x0 - fuzz && x < x0 + fuzz) - return (x0 * 3 + x) / 4; - if (x > x0 - fuzz * 2 && x < x0 + fuzz * 2) - return (x0 + x) / 2; - return x; + if (val > m->val - m->fuzz / 2 && val < m->val + m->fuzz / 2) + return m->val; + if (val > m->val - m->fuzz && val < m->val + m->fuzz) + return (m->val * 3 + val) / 4; + if (val > m->val - m->fuzz * 2 && val < m->val + m->fuzz * 2) + return (m->val + val) / 2; + return val; +} + +static int move_reset(struct filter_model *m, float val) +{ + m->delta = 0; + m->tickle = 0; + m->active = 0; + m->val = val; + m->orig = val; +} + +static int move_update(struct filter_model *m, float val) +{ + m->delta = val - m->val; + m->tickle = fabs(m->delta) > 0; + m->val = val; + if (!m->active && fabs(val - m->orig) > m->bar) + m->active = 1; + return m->active; } void gru_init_motion(struct grail *ge, const struct touch_dev_caps *caps) @@ -107,44 +126,63 @@ void gru_init_motion(struct grail *ge, const struct touch_dev_caps *caps) float x = caps->info[TP_POS_X].maximum - caps->info[TP_POS_X].minimum; float y = caps->info[TP_POS_Y].maximum - caps->info[TP_POS_Y].minimum; float r = sqrt(x * x + y * y); - state->xfuzz = x / SN_MOVE; - state->yfuzz = y / SN_MOVE; - state->rfuzz = r / SN_ZOOM; - state->afuzz = r / SN_ROTATE; - state->xbar = BAR_MOVE * state->xfuzz; - state->ybar = BAR_MOVE * state->yfuzz; - state->rbar = BAR_ZOOM * state->rfuzz; - state->abar = BAR_ROTATE * state->afuzz; + state->x.fuzz = x / SN_MOVE; + state->y.fuzz = y / SN_MOVE; + state->r.fuzz = r / SN_ZOOM; + state->a.fuzz = r / SN_ROTATE; + state->x.bar = BAR_MOVE * state->x.fuzz; + state->y.bar = BAR_MOVE * state->y.fuzz; + state->r.bar = BAR_ZOOM * state->r.fuzz; + state->a.bar = BAR_ROTATE * state->a.fuzz; + state->motion = 0; } -void gru_reset_motion(struct grail *ge, - const struct touch_frame *frame) +void gru_motion(struct grail *ge, + const struct touch_frame *frame) { struct gesture_recognizer *gru = ge->gru; struct move_model *state = &gru->move; - compute_position(&state->x, &state->y, frame); - state->r = compute_radius(state->x, state->y, frame); - state->a = 0; - state->ntouch = frame->nactive; + int na = 0, nt = frame->nactive; + float x, y, r, a; + compute_position(&x, &y, frame); + if (nt < 2 || frame->ncreate || frame->ndestroy) { + r = compute_radius(x, y, frame); + a = 0; + move_reset(&state->x, x); + move_reset(&state->y, y); + move_reset(&state->r, r); + move_reset(&state->a, a); + state->motion = 0; + } else { + x = move_filter(&state->x, x); + y = move_filter(&state->y, y); + r = compute_radius(x, y, frame); + r = move_filter(&state->r, r); + a = state->a.val + compute_rotation(x, y, r, &gru->frame, frame); + //a = move_filter(&state->a, a); + na += move_update(&state->x, x); + na += move_update(&state->y, y); + na += move_update(&state->r, r); + na += move_update(&state->a, a); + state->motion = 1; + } + state->nactive = na; + state->ntouch = nt; + state->time = frame->time; } -void gru_compute_motion(struct grail *ge, - const struct touch_frame *frame) +void gru_event(struct grail *ge, int gid, + const struct move_model *move, + const grail_prop_t *prop, int nprop) { - struct gesture_inserter *gin = ge->gin; - struct gesture_recognizer *gru = ge->gru; - struct move_model *state = &gru->move; - float x, y, r, a; - compute_position(&x, &y, frame); - x = move_filter(x, state->x, state->xfuzz); - y = move_filter(y, state->y, state->yfuzz); - r = compute_radius(x, y, frame); - r = move_filter(r, state->r, state->rfuzz); - a = state->a + compute_rotation(x, y, r, &gru->frame, frame); - a = move_filter(a, state->a, state->afuzz); - state->x = x; - state->y = y; - state->r = r; - state->a = a; - state->ntouch = frame->nactive; + gin_gid_event(ge, gid, + move->x.val, move->y.val, move->ntouch, + prop, nprop, + GRAIL_STATUS_UPDATE); } + +void gru_end(struct grail *ge, int gid, const struct move_model *move) +{ + gin_gid_end(ge, gid, move->x.val, move->y.val, move->ntouch); +} + diff --git a/src/grail-gestures.h b/src/grail-gestures.h index 70a5a98..b8f46d4 100644 --- a/src/grail-gestures.h +++ b/src/grail-gestures.h @@ -27,59 +27,47 @@ #include "grail-inserter.h" +struct filter_model { + float delta, val, orig, fuzz, bar; + int tickle, active; +}; + struct move_model { - float xfuzz, yfuzz, rfuzz, afuzz; - float xbar, ybar, rbar, abar; - float x, y, r, a; - int ntouch; + struct filter_model x, y, r, a; + int motion, nactive, ntouch; + float dx, dy, dr, da; + grail_time_t time; }; void gru_init_motion(struct grail *ge, const struct touch_dev_caps *caps); -void gru_reset_motion(struct grail *ge, - const struct touch_frame *frame); -void gru_compute_motion(struct grail *ge, - const struct touch_frame *frame); - -struct scroll_model { - float x, y; - int active, moving, geslot; -}; - -void gru_reset_scroll(struct grail *ge, - const struct touch_frame *frame); -int gru_scroll(struct grail *ge, - const struct touch_frame *frame); - -struct zoom_model { - float r; - int active, zooming, geslot; -}; +void gru_motion(struct grail *ge, + const struct touch_frame *frame); +void gru_event(struct grail *ge, int gid, + const struct move_model *move, + const grail_prop_t *prop, int nprop); -void gru_reset_zoom(struct grail *ge, - const struct touch_frame *frame); -int gru_zoom(struct grail *ge, - const struct touch_frame *frame); - -struct rotate_model { - float a; - int active, rotating, geslot; +struct combo_model { + int active, gid; }; -void gru_reset_rotate(struct grail *ge, - const struct touch_frame *frame); +int gru_pan(struct grail *ge, + const struct touch_frame *frame); +int gru_pinch(struct grail *ge, + const struct touch_frame *frame); int gru_rotate(struct grail *ge, const struct touch_frame *frame); +int gru_combo(struct grail *ge, + const struct touch_frame *frame); -struct combo_model { - float x, y, r, a; - int active, running, geslot; +struct tapping_model { + grail_time_t start; + int status, ntouch; + int active, gid; }; -void gru_reset_combo(struct grail *ge, - const struct touch_frame *frame); -int gru_combo(struct grail *ge, - const struct touch_frame *frame); +int gru_tapping(struct grail *ge, + const struct touch_frame *frame); #endif diff --git a/src/grail-inserter.c b/src/grail-inserter.c index 3927875..4bf78d3 100644 --- a/src/grail-inserter.c +++ b/src/grail-inserter.c @@ -29,6 +29,24 @@ static const int MAX_GESTURE_ID = 0xfff; +struct gesture_inserter { + struct slot_state state[DIM_INSTANCE]; + grail_mask_t unused[DIM_INSTANCE_BYTES]; + grail_mask_t fresh[DIM_INSTANCE_BYTES]; + grail_mask_t used[DIM_INSTANCE_BYTES]; + grail_time_t time; + int gestureid; +}; + +static int find_gslot(const struct gesture_inserter *gin, int gid) +{ + int i; + grail_mask_foreach(i, gin->used, sizeof(gin->used)) + if (gin->state[i].id == gid) + return i; + return -1; +} + static void send_event(struct grail *ge, struct slot_state *s, const struct gesture_event *ev) { @@ -151,7 +169,7 @@ void gin_frame_end(struct grail *ge, grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; if (!s->nclient || s->priority < discard) - gin_gesture_discard(gin, i); + gin_gid_discard(ge, s->id); } grail_mask_foreach(i, gin->used, sizeof(gin->used)) { @@ -169,22 +187,22 @@ void gin_frame_end(struct grail *ge, grail_mask_foreach(i, gin->used, sizeof(gin->used)) { struct slot_state *s = &gin->state[i]; if (s->status == GRAIL_STATUS_END) - gin_gesture_discard(gin, i); + gin_gid_discard(ge, s->id); } if (grail_mask_count(span, sizeof(span))) grail_mask_set(filtered, EV_ABS); } -int gin_gesture_begin(struct grail *ge, int type, int priority, - const grail_mask_t *span, int nspan) +int gin_gid_begin_select(struct grail *ge, int type, int priority, + const grail_mask_t *span, int nspan) { struct gesture_inserter *gin = ge->gin; struct slot_state *s; - int geslot = grail_mask_get_first(gin->unused, sizeof(gin->unused)); - if (geslot < 0) + int i = grail_mask_get_first(gin->unused, sizeof(gin->unused)); + if (i < 0) return -1; - s = &gin->state[geslot]; + s = &gin->state[i]; s->type = type; s->priority = priority; s->id = gin->gestureid++ & MAX_GESTURE_ID; @@ -192,47 +210,72 @@ int gin_gesture_begin(struct grail *ge, int type, int priority, s->nclient = 0; memcpy(s->span, span, nspan); gebuf_clear(&s->buf); - grail_mask_clear(gin->unused, geslot); - grail_mask_set(gin->fresh, geslot); - grail_mask_set(gin->used, geslot); - return geslot; -} - -void gin_gesture_end(struct gesture_inserter *gin, int geslot) -{ - gin->state[geslot].status = GRAIL_STATUS_END; + grail_mask_clear(gin->unused, i); + grail_mask_set(gin->fresh, i); + grail_mask_set(gin->used, i); + return s->id; } -void gin_gesture_discard(struct gesture_inserter *gin, int geslot) +int gin_gid_begin(struct grail *ge, int type, const struct touch_frame *frame) { - gebuf_clear(&gin->state[geslot].buf); - gin_gesture_end(gin, geslot); - grail_mask_clear(gin->used, geslot); - grail_mask_set(gin->unused, geslot); + return gin_gid_begin_select(ge, type, 1, + frame->touches, sizeof(frame->touches)); } -void gin_gesture_discard_type(struct gesture_inserter *gin, int type) +void gin_gid_discard(struct grail *ge, int gid) { - int i; - grail_mask_foreach(i, gin->used, sizeof(gin->used)) - if (gin->state[i].type == type) - gin_gesture_discard(gin, i); + struct gesture_inserter *gin = ge->gin; + struct slot_state *s; + int i = find_gslot(gin, gid); + if (i < 0) + return; + s = &gin->state[i]; + gebuf_clear(&s->buf); + s->status = GRAIL_STATUS_END; + grail_mask_clear(gin->used, i); + grail_mask_set(gin->unused, i); } -void gin_gesture_event(struct gesture_inserter *gin, int geslot, - float x, float y, int ntouch, - const grail_prop_t *prop, int nprop) +void gin_gid_event(struct grail *ge, int gid, + float x, float y, int ntouch, + const grail_prop_t *prop, int nprop, + int status) { - struct slot_state *s = &gin->state[geslot]; + struct gesture_inserter *gin = ge->gin; struct gesture_event ev; + struct slot_state *s; + int i = find_gslot(gin, gid); + if (i < 0) + return; + s = &gin->state[i]; ev.ntouch = ntouch; ev.nprop = nprop; ev.time = gin->time; ev.pos.x = x; ev.pos.y = y; memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t)); - if (s->status == GRAIL_STATUS_BEGIN) - s->status = GRAIL_STATUS_UPDATE; gebuf_put(&s->buf, &ev); + if (s->status == GRAIL_STATUS_BEGIN) + s->status = status; } +void gin_gid_end(struct grail *ge, int gid, + float x, float y, int ntouch) +{ + struct gesture_inserter *gin = ge->gin; + struct gesture_event ev; + struct slot_state *s; + int i = find_gslot(gin, gid); + if (i < 0) + return; + s = &gin->state[i]; + if (s->status != GRAIL_STATUS_BEGIN) { + ev.ntouch = ntouch; + ev.nprop = 0; + ev.time = gin->time; + ev.pos.x = x; + ev.pos.y = y; + gebuf_put(&s->buf, &ev); + } + s->status = GRAIL_STATUS_END; +} diff --git a/src/grail-inserter.h b/src/grail-inserter.h index cca71d2..c76c0e0 100644 --- a/src/grail-inserter.h +++ b/src/grail-inserter.h @@ -48,15 +48,6 @@ struct slot_state { struct gebuf buf; }; -struct gesture_inserter { - struct slot_state state[DIM_INSTANCE]; - grail_mask_t unused[DIM_INSTANCE_BYTES]; - grail_mask_t fresh[DIM_INSTANCE_BYTES]; - grail_mask_t used[DIM_INSTANCE_BYTES]; - grail_time_t time; - int gestureid; -}; - int gin_init(struct grail *ge); void gin_destroy(struct grail *ge); @@ -64,14 +55,16 @@ void gin_frame_begin(struct grail *ge, const struct touch_frame *frame); void gin_frame_end(struct grail *ge, grail_mask_t *filtered, int max_filtered, const struct touch_frame *frame); -int gin_gesture_begin(struct grail *ge, int type, int priority, - const grail_mask_t *span, int nspan); -void gin_gesture_end(struct gesture_inserter *gin, int geslot); -void gin_gesture_discard(struct gesture_inserter *gin, int geslot); -void gin_gesture_discard_type(struct gesture_inserter *gin, int type); +int gin_gid_begin_select(struct grail *ge, int type, int priority, + const grail_mask_t *span, int nspan); +int gin_gid_begin(struct grail *ge, int type, const struct touch_frame *frame); +void gin_gid_discard(struct grail *ge, int gid); -void gin_gesture_event(struct gesture_inserter *gin, int geslot, - float x, float y, int ntouch, - const grail_prop_t *prop, int nprop); +void gin_gid_event(struct grail *ge, int gid, + float x, float y, int ntouch, + const grail_prop_t *prop, int nprop, + int status); +void gin_gid_end(struct grail *ge, int gid, + float x, float y, int ntouch); #endif diff --git a/src/grail-recognizer.c b/src/grail-recognizer.c index 1e7a8bf..bed704e 100644 --- a/src/grail-recognizer.c +++ b/src/grail-recognizer.c @@ -27,8 +27,6 @@ #include #include -static const touch_time_t DROP_TIMEOUT_MS = 100; - int gru_init(struct grail *ge, const struct touch_dev_caps *caps) { struct gesture_recognizer *gru; @@ -46,32 +44,15 @@ void gru_destroy(struct grail *ge) ge->gru = NULL; } -static void reset_gru_state(struct grail *ge, const struct touch_frame *frame) -{ - gru_reset_combo(ge, frame); - gru_reset_rotate(ge, frame); - gru_reset_zoom(ge, frame); - gru_reset_scroll(ge, frame); - gru_reset_motion(ge, frame); -} - void gru_recognize(struct grail *ge, const struct touch_frame *frame) { - struct gesture_recognizer *gru = ge->gru; - struct move_model *move = &gru->move; if (!ge->gin || !ge->gru) return; - if (frame->nactive < move->ntouch && - frame->time < gru->frame.time + DROP_TIMEOUT_MS) - return; - if (frame->nactive < 2 || frame->ncreate || frame->ndestroy) { - reset_gru_state(ge, frame); - return; - } - gru_compute_motion(ge, frame); - gru_scroll(ge, frame); - gru_zoom(ge, frame); + gru_motion(ge, frame); + gru_pan(ge, frame); + gru_pinch(ge, frame); gru_rotate(ge, frame); gru_combo(ge, frame); - gru->frame = *frame; + gru_tapping(ge, frame); + ge->gru->frame = *frame; } diff --git a/src/grail-recognizer.h b/src/grail-recognizer.h index 247687d..d3b24b3 100644 --- a/src/grail-recognizer.h +++ b/src/grail-recognizer.h @@ -30,10 +30,11 @@ struct gesture_recognizer { struct touch_frame frame; struct move_model move; - struct scroll_model scroll; - struct zoom_model zoom; - struct rotate_model rotate; + struct combo_model pan; + struct combo_model pinch; + struct combo_model rotate; struct combo_model combo; + struct tapping_model tapping; }; int gru_init(struct grail *ge, const struct touch_dev_caps *caps); -- cgit v1.2.3