/***************************************************************************** * * 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 TAP_MAX_GAP_MS = 300; static const int fm_mask = 0x03; 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 (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) { 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 > TAP_MAX_GAP_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; prop[GRAIL_PROP_TAP_DT] = move->time - state->start; gin_gid_event(ge, state->gid, move->fm[FM_X].value, move->fm[FM_Y].value, state->ntouch, prop, 1, 1); state->status = TAP_BEGIN; state->ntouch = 0; state->active = 0; return 1; }