/***************************************************************************** * * grail - Gesture Recognition And Instantiation Library * * Copyright (C) 2010 Canonical Ltd. * Copyright (C) 2010 Henrik Rydberg * * 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 . * ****************************************************************************/ #include "grail-recognizer.h" #include static const int TAP_BEGIN = 0; static const int TAP_END = 1; static const int TAP_CANCEL = 2; static const int TAP_MIN_GAP_MS = 25; static const int fm_mask = 0x03; static void set_props(const struct gesture_inserter *gin, struct tapping_model *s, const struct move_model *m, const struct touch_frame *frame) { s->prop[GRAIL_PROP_TAP_DT] = m->time - s->start; s->prop[GRAIL_PROP_TAP_X] = gin_prop_x(gin, m->fm[FM_X].value); s->prop[GRAIL_PROP_TAP_Y] = gin_prop_y(gin, m->fm[FM_Y].value); s->nprop = 3; s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame); } 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; if (move->ntouch) { if (state->status == TAP_CANCEL) return 0; state->status = TAP_BEGIN; if (!state->ntouch) state->start = move->time; if (move->ntouch >= state->ntouch) { set_props(ge->gin, state, move, frame); } if (move->ntouch > state->ntouch) { state->ntouch = move->ntouch; if (state->active) { gin_gid_discard(ge, state->gid); state->active = 0; } } if (!state->active) { int type = GRAIL_TYPE_TAP1 + state->ntouch - 1; state->gid = gin_gid_begin(ge, type, PRIO_TAP, frame); state->active = 1; } } else if (state->status == TAP_BEGIN && state->ntouch) { state->status = TAP_END; } else { state->status = TAP_BEGIN; state->ntouch = 0; return 0; } if (state->ntouch < 1 || state->ntouch > 5) state->status = TAP_CANCEL; if (move->time - state->start > move->fm[FM_X].bar_ms) state->status = TAP_CANCEL; if (state->status == TAP_END && move->time - state->start < TAP_MIN_GAP_MS) state->status = TAP_CANCEL; if (move->active & fm_mask) state->status = TAP_CANCEL; if (state->status == TAP_CANCEL) { if (state->active) { gin_gid_discard(ge, state->gid); state->active = 0; } state->ntouch = 0; return 0; } if (state->status != TAP_END || move->time - state->start < TAP_MIN_GAP_MS) return 0; state->prop[GRAIL_PROP_TAP_DT] = move->time - state->start; gin_gid_event(ge, state->gid, state->prop[GRAIL_PROP_TAP_X], state->prop[GRAIL_PROP_TAP_Y], state->ntouch, state->prop, state->nprop, 1); state->status = TAP_BEGIN; state->ntouch = 0; state->active = 0; return 1; }