=== modified file 'include/grail-bits.h'
--- include/grail-bits.h 2011-04-12 16:35:37 +0000
+++ include/grail-bits.h 2011-04-27 19:43:23 +0000
@@ -49,6 +49,7 @@
void grail_mask_set_mask(grail_mask_t *a, const grail_mask_t *b, int bytes);
void grail_mask_clear_mask(grail_mask_t *a, const grail_mask_t *b, int bytes);
+int grail_mask_inner(const grail_mask_t *a, const grail_mask_t *b, int bytes);
int grail_mask_count(const grail_mask_t *mask, int bytes);
int grail_mask_get_first(const grail_mask_t *mask, int bytes);
=== modified file 'include/grail.h'
--- include/grail.h 2011-04-12 16:35:37 +0000
+++ include/grail.h 2011-04-27 19:43:23 +0000
@@ -128,6 +128,27 @@
*/
const struct grail_frame *grail_pump_frame(grail_handle ge,
const struct utouch_frame *frame);
+/**
+ * grail_pivot_type - Option for determining location of pivot point
+ * @GRAIL_CENTROID: use the centroid of the touch points as the pivot point
+ * @GRAIL_CENTER_OF_ROTATION: set the pivot point such that there is no
+ translation in the transformation matrix ("instant center of rotation")
+ * @GRAIL_CONVEX_HULL_RADIUS: Minimize translation while confining the pivot
+ point to a circle around the centroid approximating the radius of the
+ convex hull of the touch points
+ *
+ * The gesture transformation matrix and pivot point are dependent. This means
+ * a transformation can be found for any given pivot point. Depending on the use
+ * case, one pivot point location may be better than another. If the use case
+ * involves only dragging gestures, GRAIL_CENTROID is best. If the use case
+ * involves only rotation gestures, GRAIL_CENTER_OF_ROTATION or
+ * may be better GRAIL_CONVEX_HULL_RADIUS.
+ */
+enum grail_pivot_type {
+ GRAIL_CENTROID = 0,
+ GRAIL_CENTER_OF_ROTATION,
+ GRAIL_CONVEX_HULL_RADIUS
+};
/**
* struct grail_client_id - Gesture client information
@@ -157,8 +178,6 @@
/**
* struct grail_control - control parameters of grail
* @glue_ms: minimum time to hold activation (ms)
- * @thresh_drag: minimum moveness for drag
- * @thresh_scale: maximum moveness for rotate and scale
* @bar_x: minimum horizontal distance to activate (surface width fraction)
* @bar_y: minimum vertical distance to activate (surface height fraction)
* @bar_scale: minimum scaling to activate (fraction)
@@ -170,17 +189,11 @@
*
* The parameters are used to tune the behavior of the gesture recognition.
*
- * The moveness is a number between zero and one denoting the
- * character of the current transform. Zero means pure rotate and
- * scale, one means pure drag.
- *
* Later versions of this struct may grow in size, but will remain
* binary compatible with older versions.
*/
struct grail_control {
float glue_ms;
- float thresh_drag;
- float thresh_scale;
float bar_x;
float bar_y;
float bar_scale;
@@ -189,6 +202,7 @@
float drop_y_ms;
float drop_scale_ms;
float drop_angle_ms;
+ enum grail_pivot_type pivot_type;
};
/**
@@ -262,7 +276,6 @@
struct grail_coord velocity;
float radius2;
float transform[6];
- float moveness;
struct grail_coord pivot;
struct grail_coord drag;
float scale2;
@@ -283,8 +296,12 @@
const struct grail_coord *p)
{
const float *T = slot->transform;
- q->x = T[0] * p->x + T[1] * p->y + T[2];
- q->y = T[3] * p->x + T[4] * p->y + T[5];
+ q->x = T[0] * (p->x - slot->pivot.x) +
+ T[1] * (p->y - slot->pivot.y) +
+ T[2] + slot->pivot.x;
+ q->y = T[3] * (p->x - slot->pivot.x) +
+ T[4] * (p->y - slot->pivot.y) +
+ T[5] + slot->pivot.y;
}
/**
@@ -349,21 +366,6 @@
};
/**
- * grail_open - open a grail device
- * @ge: the grail device to open
- * @fd: file descriptor of the kernel device
- *
- * Initialize the internal grail structures and configure it by reading the
- * protocol capabilities through the file descriptor.
- *
- * The callbacks, parameters and priv pointer should be set prior to this
- * call.
- *
- * Returns zero on success, negative error number otherwise.
- */
-int grail_open(struct grail *ge, int fd);
-
-/**
* grail_idle - check state of kernel device
* @ge: the grail device in use
* @fd: file descriptor of the kernel device
@@ -391,16 +393,6 @@
int grail_pull(struct grail *ge, int fd);
/**
- * grail_close - close the grail device
- * @ge: the grail device to close
- * @fd: file descriptor of the kernel device
- *
- * Deallocates all memory associated with grail, and clears the grail
- * structure.
- */
-void grail_close(struct grail *ge, int fd);
-
-/**
* grail_set_bbox - set the grail unit bounding box
* @ge: the grail device in use
* @min: the minimum (lower-left) corner of the bounding box
@@ -443,6 +435,22 @@
*/
const struct utouch_frame *grail_get_contact_frame(const struct grail *ge);
+/**
+ * grail_get_gesture_frame - get current gesture frame
+ * @ge: the grail device in use
+ *
+ * Return the gesture frame currently being processed. If called from
+ * within a gesture callback, it is guaranteed to return the frame
+ * corresponding to the gesture.
+ *
+ * The returned pointer can be NULL if no input has yet been extracted
+ * through the grail instance.
+ *
+ * The frame pointer is ABI agnostic, owned by the grail instance, and
+ * has grail scope.
+ */
+const struct grail_frame *grail_get_gesture_frame(const struct grail *ge);
+
#ifndef GRAIL_NO_LEGACY_API
struct grail_contact {
@@ -457,6 +465,8 @@
float pressure;
};
+int grail_open(struct grail *ge, int fd);
+void grail_close(struct grail *ge, int fd);
void grail_filter_abs_events(struct grail *ge, int usage);
int grail_get_contacts(const struct grail *ge,
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2011-04-12 16:35:23 +0000
+++ src/Makefile.am 2011-04-27 19:43:23 +0000
@@ -15,13 +15,6 @@
grail-bits.c \
grail-inserter.c \
grail-inserter.h \
- grail-gestures.c \
- grail-gestures.h \
- gestures-touch.c \
- gestures-drag.c \
- gestures-pinch.c \
- gestures-rotate.c \
- gestures-tapping.c \
grail-recognizer.c \
grail-recognizer.h \
grail-event.c \
=== removed file 'src/gestures-drag.c'
--- src/gestures-drag.c 2011-04-12 16:35:37 +0000
+++ src/gestures-drag.c 1970-01-01 00:00:00 +0000
@@ -1,135 +0,0 @@
-/*****************************************************************************
- *
- * grail - Gesture Recognition And Instantiation Library
- *
- * Copyright (C) 2010-2011 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 .
- *
- ****************************************************************************/
-
-#include "grail-recognizer.h"
-#include
-#include
-
-static const int getype[DIM_TOUCH + 1] = {
- -1,
- GRAIL_TYPE_DRAG1,
- GRAIL_TYPE_DRAG2,
- GRAIL_TYPE_DRAG3,
- GRAIL_TYPE_DRAG4,
- GRAIL_TYPE_DRAG5,
-};
-
-static void set_props(const struct gesture_inserter *gin,
- struct combo_model *s, const struct move_model *m,
- const struct utouch_frame *frame)
-{
- if (m->single) {
- s->prop[GRAIL_PROP_DRAG_DX] = m->fm[FM_X].raw_delta;
- s->prop[GRAIL_PROP_DRAG_DY] = m->fm[FM_Y].raw_delta;
- } else {
- s->prop[GRAIL_PROP_DRAG_DX] = m->fm[FM_X].action_delta;
- s->prop[GRAIL_PROP_DRAG_DY] = m->fm[FM_Y].action_delta;
- }
- s->prop[GRAIL_PROP_DRAG_VX] = m->fm[FM_X].velocity;
- s->prop[GRAIL_PROP_DRAG_VY] = m->fm[FM_Y].velocity;
- s->prop[GRAIL_PROP_DRAG_X] = m->fm[FM_X].value;
- s->prop[GRAIL_PROP_DRAG_Y] = m->fm[FM_Y].value;
- s->nprop = 6;
- s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
-}
-
-static const int fm_mask = 0x03;
-
-int gru_drag(struct grail *ge,
- const struct utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct combo_model *state = &gru->drag;
- struct move_model *move = &gru->move;
- int mask = state->active ? (move->active & fm_mask) : fm_mask;
- if (!move->multi && !move->single) {
- if (state->active) {
- gru_end(ge, state->gid, move,
- state->prop, state->nprop);
- state->active = 0;
- }
- }
- if ((move->timeout & fm_mask) == fm_mask) {
- if (state->active) {
- gin_gid_timeout(ge, state->gid);
- }
- }
- if (!state->active) {
- int type = getype[move->ntouch];
- if (type < 0)
- return 0;
- state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
- state->active = 1;
- }
- if (!(move->tickle & mask))
- return 0;
- if (!(move->active & fm_mask))
- return 0;
- set_props(ge->gin, state, move, frame);
- gru_event(ge, state->gid, move, state->prop, state->nprop);
- return 1;
-}
-
-int gru_windrag(struct grail *ge,
- const struct utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct combo_model *state = &gru->windrag;
- struct move_model *move = &gru->move;
- int mask = state->active ? (move->active & fm_mask) : fm_mask;
- if (!move->multi && !move->single) {
- if (state->active && out_of_bounds(state, move)) {
- gru_end(ge, state->gid, move,
- state->prop, state->nprop);
- state->active = 0;
- }
- }
- if ((move->timeout & fm_mask) == fm_mask) {
- if (state->active) {
- gin_gid_timeout(ge, state->gid);
- }
- }
- if (!state->active) {
- if (move->ntouch == 4) {
- state->gid = gin_gid_begin(ge, GRAIL_TYPE_MDRAG,
- PRIO_META, frame);
- state->mintouch = 1;
- state->maxtouch = 4;
- state->active = 1;
- } else if (move->ntouch == 3) {
- state->gid = gin_gid_begin(ge, GRAIL_TYPE_EDRAG,
- PRIO_ENV, frame);
- state->mintouch = 1;
- state->maxtouch = 3;
- state->active = 1;
- } else {
- return 0;
- }
- }
- if (!(move->tickle & mask))
- return 0;
- if (!(move->active & fm_mask))
- return 0;
- set_props(ge->gin, state, move, frame);
- gru_event(ge, state->gid, move, state->prop, state->nprop);
- return 1;
-}
-
=== removed file 'src/gestures-pinch.c'
--- src/gestures-pinch.c 2011-04-12 16:35:37 +0000
+++ src/gestures-pinch.c 1970-01-01 00:00:00 +0000
@@ -1,129 +0,0 @@
-/*****************************************************************************
- *
- * grail - Gesture Recognition And Instantiation Library
- *
- * Copyright (C) 2010-2011 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 .
- *
- ****************************************************************************/
-
-#include "grail-recognizer.h"
-#include
-#include
-
-static const int getype[DIM_TOUCH + 1] = {
- 0,
- 0,
- GRAIL_TYPE_PINCH2,
- GRAIL_TYPE_PINCH3,
- GRAIL_TYPE_PINCH4,
- GRAIL_TYPE_PINCH5,
-};
-
-static const int fm_mask = 0x04;
-
-static void set_props(const struct gesture_inserter *gin,
- struct combo_model *s,
- const struct move_model *m,
- const struct utouch_frame *frame)
-{
- s->prop[GRAIL_PROP_PINCH_DR] = m->fm[FM_R].action_delta;
- s->prop[GRAIL_PROP_PINCH_VR] = m->fm[FM_R].velocity;
- s->prop[GRAIL_PROP_PINCH_R] = m->fm[FM_R].value;
- s->nprop = 3;
- s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
-}
-
-int gru_pinch(struct grail *ge,
- const struct utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct combo_model *state = &gru->pinch;
- struct move_model *move = &gru->move;
- int mask = state->active ? (move->active & fm_mask) : fm_mask;
- if (!move->multi && !move->single) {
- if (state->active) {
- gru_end(ge, state->gid, move,
- state->prop, state->nprop);
- state->active = 0;
- }
- return 0;
- }
- if ((move->timeout & fm_mask) == fm_mask) {
- if (state->active) {
- gin_gid_timeout(ge, state->gid);
- }
- }
- if (!(move->tickle & mask))
- return 0;
- if (!state->active) {
- int type = getype[move->ntouch];
- if (!type)
- return 0;
- state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
- state->active = 1;
- }
- if (!(move->active & fm_mask))
- return 0;
- set_props(ge->gin, state, move, frame);
- gru_event(ge, state->gid, move, state->prop, state->nprop);
- return 1;
-}
-
-int gru_winpinch(struct grail *ge,
- const struct utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct combo_model *state = &gru->winpinch;
- struct move_model *move = &gru->move;
- int mask = state->active ? (move->active & fm_mask) : fm_mask;
- if (!move->multi) {
- if (state->active && out_of_bounds(state, move)) {
- gru_end(ge, state->gid, move,
- state->prop, state->nprop);
- state->active = 0;
- }
- return 0;
- }
- if ((move->timeout & fm_mask) == fm_mask) {
- if (state->active) {
- gin_gid_timeout(ge, state->gid);
- }
- }
- if (!(move->tickle & mask))
- return 0;
- if (!state->active) {
- if (move->ntouch == 4) {
- state->gid = gin_gid_begin(ge, GRAIL_TYPE_MPINCH,
- PRIO_META, frame);
- state->mintouch = 2;
- state->maxtouch = 4;
- state->active = 1;
- } else if (move->ntouch == 3) {
- state->gid = gin_gid_begin(ge, GRAIL_TYPE_EPINCH,
- PRIO_ENV, frame);
- state->mintouch = 2;
- state->maxtouch = 3;
- state->active = 1;
- } else {
- return 0;
- }
- }
- if (!(move->active & fm_mask))
- return 0;
- set_props(ge->gin, state, move, frame);
- gru_event(ge, state->gid, move, state->prop, state->nprop);
- return 1;
-}
=== removed file 'src/gestures-rotate.c'
--- src/gestures-rotate.c 2011-04-12 16:35:37 +0000
+++ src/gestures-rotate.c 1970-01-01 00:00:00 +0000
@@ -1,128 +0,0 @@
-/*****************************************************************************
- *
- * grail - Gesture Recognition And Instantiation Library
- *
- * Copyright (C) 2010-2011 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 .
- *
- ****************************************************************************/
-
-#include "grail-recognizer.h"
-#include
-#include
-
-static const int getype[DIM_TOUCH + 1] = {
- 0,
- 0,
- GRAIL_TYPE_ROTATE2,
- GRAIL_TYPE_ROTATE3,
- GRAIL_TYPE_ROTATE4,
- GRAIL_TYPE_ROTATE5,
-};
-
-static const int fm_mask = 0x08;
-
-static void set_props(const struct gesture_inserter *gin,
- struct combo_model *s, const struct move_model *m,
- const struct utouch_frame *frame)
-{
- s->prop[GRAIL_PROP_ROTATE_DA] = m->fm[FM_A].action_delta;
- s->prop[GRAIL_PROP_ROTATE_VA] = m->fm[FM_A].velocity;
- s->prop[GRAIL_PROP_ROTATE_A] = m->fm[FM_A].value;
- s->nprop = 3;
- s->nprop += gin_add_contact_props(gin, s->prop + s->nprop, frame);
-}
-
-int gru_rotate(struct grail *ge,
- const struct utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct combo_model *state = &gru->rotate;
- struct move_model *move = &gru->move;
- int mask = state->active ? (move->active & fm_mask) : fm_mask;
- if (!move->multi && !move->single) {
- if (state->active) {
- gru_end(ge, state->gid, move,
- state->prop, state->nprop);
- state->active = 0;
- }
- return 0;
- }
- if ((move->timeout & fm_mask) == fm_mask) {
- if (state->active) {
- gin_gid_timeout(ge, state->gid);
- }
- }
- if (!(move->tickle & mask))
- return 0;
- if (!state->active) {
- int type = getype[move->ntouch];
- if (!type)
- return 0;
- state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
- state->active = 1;
- }
- if (!(move->active & fm_mask))
- return 0;
- set_props(ge->gin, state, move, frame);
- gru_event(ge, state->gid, move, state->prop, state->nprop);
- return 1;
-}
-
-int gru_winrotate(struct grail *ge,
- const struct utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct combo_model *state = &gru->winrotate;
- struct move_model *move = &gru->move;
- int mask = state->active ? (move->active & fm_mask) : fm_mask;
- if (!move->multi) {
- if (state->active && out_of_bounds(state, move)) {
- gru_end(ge, state->gid, move,
- state->prop, state->nprop);
- state->active = 0;
- }
- return 0;
- }
- if ((move->timeout & fm_mask) == fm_mask) {
- if (state->active) {
- gin_gid_timeout(ge, state->gid);
- }
- }
- if (!(move->tickle & mask))
- return 0;
- if (!state->active) {
- if (move->ntouch == 4) {
- state->gid = gin_gid_begin(ge, GRAIL_TYPE_MROTATE,
- PRIO_META, frame);
- state->mintouch = 2;
- state->maxtouch = 4;
- state->active = 1;
- } else if (move->ntouch == 3) {
- state->gid = gin_gid_begin(ge, GRAIL_TYPE_EROTATE,
- PRIO_ENV, frame);
- state->mintouch = 2;
- state->maxtouch = 3;
- state->active = 1;
- } else {
- return 0;
- }
- }
- if (!(move->active & fm_mask))
- return 0;
- set_props(ge->gin, state, move, frame);
- gru_event(ge, state->gid, move, state->prop, state->nprop);
- return 1;
-}
=== removed file 'src/gestures-tapping.c'
--- src/gestures-tapping.c 2011-04-12 16:35:37 +0000
+++ src/gestures-tapping.c 1970-01-01 00:00:00 +0000
@@ -1,100 +0,0 @@
-/*****************************************************************************
- *
- * grail - Gesture Recognition And Instantiation Library
- *
- * Copyright (C) 2010-2011 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 .
- *
- ****************************************************************************/
-
-#include "grail-recognizer.h"
-#include
-
-static const int fm_mask = 0x07;
-
-static void set_props(const struct gesture_inserter *gin,
- struct tapping_model *s, const struct move_model *m,
- const struct utouch_frame *frame)
-{
- s->prop[GRAIL_PROP_TAP_DT] = m->time - s->start;
- s->prop[GRAIL_PROP_TAP_X] = m->fm[FM_X].value;
- s->prop[GRAIL_PROP_TAP_Y] = 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 utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct tapping_model *state = &gru->tapping;
- struct move_model *move = &gru->move;
- state->tap = 0;
- if (frame->num_active && !frame->prev->num_active) {
- state->mintouch = 0;
- state->maxtouch = 0;
- }
- if (move->ntouch > state->maxtouch) {
- if (state->active) {
- gin_gid_discard(ge, state->gid);
- state->active = 0;
- }
- state->start = move->time;
- state->maxtouch = move->ntouch;
- set_props(ge->gin, state, move, frame);
- if (state->maxtouch <= 5) {
- int type = GRAIL_TYPE_TAP1 + state->maxtouch - 1;
- state->gid = gin_gid_begin(ge, type, PRIO_TAP, frame);
- state->active = 1;
- }
- return 0;
- }
- if (!state->active) {
- state->mintouch = move->ntouch;
- state->maxtouch = move->ntouch;
- return 0;
- }
- if (move->ntouch <= state->mintouch) {
- int x = state->prop[GRAIL_PROP_TAP_X];
- int y = state->prop[GRAIL_PROP_TAP_Y];
- int t = move->time - state->start;
- if (t > move->fm[FM_X].bar_ms) {
- gin_gid_discard(ge, state->gid);
- state->mintouch = move->ntouch;
- state->maxtouch = move->ntouch;
- state->active = 0;
- return 0;
- }
- state->tap = state->maxtouch;
- state->prop[GRAIL_PROP_TAP_DT] = t;
- gin_gid_event(ge, state->gid, x, y, state->maxtouch,
- state->prop, state->nprop, 1);
- state->mintouch = move->ntouch;
- state->maxtouch = move->ntouch;
- state->active = 0;
- return 1;
- }
- if (!move->ntouch)
- return 0;
- state->prop[GRAIL_PROP_TAP_DT] = move->time - state->start;
- if ((move->active & fm_mask) ||
- move->time - state->start > move->fm[FM_X].bar_ms) {
- gin_gid_discard(ge, state->gid);
- state->mintouch = move->ntouch;
- state->maxtouch = move->ntouch;
- state->active = 0;
- }
- return 0;
-}
=== removed file 'src/gestures-touch.c'
--- src/gestures-touch.c 2011-04-04 17:27:38 +0000
+++ src/gestures-touch.c 1970-01-01 00:00:00 +0000
@@ -1,98 +0,0 @@
-/*****************************************************************************
- *
- * 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
-#include
-
-static const int getype[DIM_TOUCH + 1] = {
- -1,
- GRAIL_TYPE_TOUCH1,
- GRAIL_TYPE_TOUCH2,
- GRAIL_TYPE_TOUCH3,
- GRAIL_TYPE_TOUCH4,
- GRAIL_TYPE_TOUCH5,
-};
-
-int gru_touch(struct grail *ge,
- const struct utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct combo_model *state = &gru->touch;
- struct move_model *move = &gru->move;
- if (frame->slot_revision != frame->prev->slot_revision) {
- if (state->active) {
- gru_end(ge, state->gid, move,
- state->prop, state->nprop);
- state->active = 0;
- }
- }
- if (!state->active) {
- int type = getype[move->ntouch];
- if (type <= 0)
- return 0;
- state->gid = gin_gid_begin(ge, type, -PRIO_GESTURE, frame);
- state->active = 1;
- }
- if (move->time - move->fm[FM_X].original_ms <= move->fm[FM_X].hold_ms)
- return 0;
- state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
- gru_event(ge, state->gid, move, state->prop, state->nprop);
- return 1;
-}
-
-int gru_wintouch(struct grail *ge,
- const struct utouch_frame *frame)
-{
- struct gesture_recognizer *gru = ge->gru;
- struct combo_model *state = &gru->wintouch;
- struct move_model *move = &gru->move;
- if (frame->slot_revision != frame->prev->slot_revision) {
- if (state->active && out_of_bounds(state, move)) {
- gru_end(ge, state->gid, move,
- state->prop, state->nprop);
- state->active = 0;
- }
- }
- if (!state->active) {
- if (move->ntouch == 4) {
- state->gid = gin_gid_begin(ge, GRAIL_TYPE_MTOUCH,
- -PRIO_META, frame);
- state->mintouch = 1;
- state->maxtouch = 4;
- state->active = 1;
- } else if (move->ntouch == 3) {
- state->gid = gin_gid_begin(ge, GRAIL_TYPE_ETOUCH,
- -PRIO_ENV, frame);
- state->mintouch = 1;
- state->maxtouch = 3;
- state->active = 1;
- } else {
- return 0;
- }
- }
- if (move->time - move->fm[FM_X].original_ms <= move->fm[FM_X].hold_ms)
- return 0;
- state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
- gru_event(ge, state->gid, move, state->prop, state->nprop);
- return 1;
-}
=== modified file 'src/grail-api.c'
--- src/grail-api.c 2011-04-12 16:35:37 +0000
+++ src/grail-api.c 2011-04-27 19:43:23 +0000
@@ -30,104 +30,11 @@
#include
#include
-#define DIM_FRAMES 100
-#define FRAME_RATE 100
-
unsigned int grail_get_version(void)
{
return GRAIL_VERSION;
}
-
-int grail_open(struct grail *ge, int fd)
-{
- struct grail_impl *x;
- struct stat fs;
- int ret;
-
- ret = fstat(fd, &fs);
- if (ret)
- return ret;
-
- x = calloc(1, sizeof(*x));
- if (!x)
- return -ENOMEM;
-
- if (!fs.st_rdev)
- x->fptest = fdopen(fd, "r");
-
- x->evemu = evemu_new(x->fptest ? "fptest" : 0);
- if (!x->evemu) {
- ret = -ENOMEM;
- goto freemem;
- }
- if (x->fptest)
- ret = evemu_read(x->evemu, x->fptest) <= 0;
- else
- ret = evemu_extract(x->evemu, fd);
- if (ret)
- goto freemem;
- if (!utouch_frame_is_supported_mtdev(x->evemu)) {
- ret = -ENODEV;
- goto freemem;
- }
-
- if (!x->fptest) {
- x->mtdev = mtdev_new_open(fd);
- if (!x->mtdev) {
- ret = -ENOMEM;
- goto freemem;
- }
- }
- x->fh = utouch_frame_new_engine(DIM_FRAMES, DIM_TOUCH, FRAME_RATE);
- if (!x->fh) {
- ret = -ENOMEM;
- goto freedev;
- }
- ret = utouch_frame_init_mtdev(x->fh, x->evemu);
- if (ret)
- goto freeframe;
-
- ge->impl = x;
-
- ret = gin_init(ge);
- if (ret)
- goto freeframe;
-
- ret = gru_init(ge);
- if (ret)
- goto freegin;
-
- return 0;
- freegin:
- gin_destroy(ge);
- freeframe:
- utouch_frame_delete_engine(x->fh);
- freedev:
- if (x->mtdev)
- mtdev_close_delete(x->mtdev);
- freemem:
- evemu_delete(x->evemu);
- if (x->fptest)
- fclose(x->fptest);
- free(x);
- ge->impl = 0;
- return ret;
-}
-
-void grail_close(struct grail *ge, int fd)
-{
- struct grail_impl *x = ge->impl;
- gru_destroy(ge);
- gin_destroy(ge);
- utouch_frame_delete_engine(x->fh);
- if (x->mtdev)
- mtdev_close_delete(x->mtdev);
- evemu_delete(x->evemu);
- if (x->fptest)
- fclose(x->fptest);
- free(x);
- ge->impl = 0;
-}
+static const float TIMEOUT_MS = 300;
int grail_idle(struct grail *ge, int fd, int ms)
{
@@ -154,6 +61,11 @@
return ge->impl->touch;
}
+const struct grail_frame *grail_get_gesture_frame(const struct grail *ge)
+{
+ return ge->impl->frame;
+}
+
static void flush_events(struct grail *ge)
{
struct grail_impl *impl = ge->impl;
@@ -219,7 +131,7 @@
struct gesture_inserter *gin = ge->gin;
return grail_mask_count(gin->used, sizeof(gin->used)) == 0 &&
- frame->time - frame->mod_time > gru->move.fm[FM_X].hold_ms;
+ frame->time - frame->mod_time > TIMEOUT_MS;
}
static void report_frame(struct grail *ge,
@@ -227,9 +139,13 @@
const struct input_event *syn)
{
struct grail_impl *impl = ge->impl;
+ const struct grail_frame *frame;
struct grail_event gev;
+ frame = grail_pump_frame(ge, touch);
+
impl->touch = touch;
+ impl->frame = frame;
if (touch->num_active && !touch->prev->num_active) {
impl->ongoing = 1;
@@ -240,7 +156,7 @@
return;
gin_frame_begin(ge, touch);
- gru_recognize(ge, touch);
+ gru_recognize(ge, frame, touch);
gin_frame_end(ge, touch);
if (!grailbuf_empty(&impl->gbuf))
=== modified file 'src/grail-bits.c'
--- src/grail-bits.c 2011-04-12 16:35:37 +0000
+++ src/grail-bits.c 2011-04-27 19:43:23 +0000
@@ -57,6 +57,15 @@
*a++ &= ~*b++;
}
+int grail_mask_inner(const grail_mask_t *a, const grail_mask_t *b, int bytes)
+{
+ int k;
+ for (k = 0; k < bytes; k++)
+ if (a[k] & b[k])
+ return 1;
+ return 0;
+}
+
int grail_mask_count(const grail_mask_t *mask, int bytes)
{
int count = 0;
=== modified file 'src/grail-frame.c'
--- src/grail-frame.c 2011-04-12 16:35:37 +0000
+++ src/grail-frame.c 2011-04-27 19:43:23 +0000
@@ -71,51 +71,26 @@
slot->center.x = x;
slot->center.y = y;
+ slot->pivot = slot->center;
slot->velocity.x = 1000 * vx;
slot->velocity.y = 1000 * vy;
slot->radius2 = r2;
}
-static void set_moveness_pivot_and_drag(struct grail_impl *impl,
- struct grail_element *slot,
- double ds, double dc)
+static void set_transform(struct grail_impl *impl, struct grail_element *slot,
+ double ds, double dc)
{
const struct grail_element *pslot = slot->prev;
double mx = slot->center.x - pslot->center.x;
double my = slot->center.y - pslot->center.y;
float *T = slot->transform;
- slot->moveness = 1;
- slot->pivot = pslot->center;
-
- if (slot->num_touches > 1) {
- double wx = (1 - dc) * mx + ds * my;
- double wy = (1 - dc) * my - ds * mx;
- double w2 = wx * wx + wy * wy;
- if (w2 > 0) {
- double s = sqrt(pslot->radius2 / w2);
- double q = (mx * mx + my * my) / w2;
- if (s < q) {
- slot->moveness = 1 - s / q;
- slot->pivot.x += s * wx;
- slot->pivot.y += s * wy;
- } else {
- slot->moveness = 0;
- slot->pivot.x += q * wx;
- slot->pivot.y += q * wy;
- }
- }
- }
-
- mx *= slot->moveness;
- my *= slot->moveness;
-
T[0] = dc;
T[1] = ds;
- T[2] = (1 - dc) * slot->pivot.x - ds * slot->pivot.y + mx;
+ T[2] = mx;
T[3] = -ds;
T[4] = dc;
- T[5] = (1 - dc) * slot->pivot.y + ds * slot->pivot.x + my;
+ T[5] = my;
slot->drag.x = pslot->drag.x + mx;
slot->drag.y = pslot->drag.y + my;
@@ -134,7 +109,6 @@
set_center_velocity_and_radius(impl, slot);
T[0] = T[4] = 1;
T[1] = T[2] = T[3] = T[5] = 0;
- slot->pivot = slot->center;
slot->drag.x = 0;
slot->drag.y = 0;
slot->scale2 = 1;
@@ -153,7 +127,7 @@
slot->active_mask = pslot->active_mask;
set_center_velocity_and_radius(impl, slot);
- set_moveness_pivot_and_drag(impl, slot, ds, dc);
+ set_transform(impl, slot, ds, dc);
slot->scale2 = pslot->scale2 * (ds * ds + dc * dc);
slot->angle = pslot->angle + ds / dc; /* atan2(ds, dc) */
@@ -175,8 +149,6 @@
slot->radius2 = pslot->radius2;
T[0] = T[4] = 1;
T[1] = T[2] = T[3] = T[5] = 0;
- slot->moveness = 1;
- slot->pivot = pslot->pivot;
slot->drag = pslot->drag;
slot->scale2 = pslot->scale2;
slot->angle = pslot->angle;
@@ -308,6 +280,141 @@
set_slot_multi(impl, slots[n++], frame, touch);
}
+/**
+ * Determine the pivot point where the transformation matrix has zero
+ * translation. Thus, T1 is equal to:
+ *
+ * T1: [ a -b 0 ]
+ * [ b a 0 ]
+ * [ 0 0 1 ]
+ *
+ * Using the equation noted in the comment for set_pivot we can solve for P1.
+ */
+static inline int center_of_rotation(float a, float b, float c, float d,
+ float x0, float y0, float *x1, float *y1)
+{
+ float div = a*a - 2*a + b*b + 1;
+
+ if (div == 0)
+ return 0;
+
+ *x1 = (a*a*x0 - a*(2*x0+c) + b*b*x0 - b*d + c + x0) / div;
+ *y1 = (a*a*y0 - a*(2*y0+d) + b*b*y0 + b*c + d + y0) / div;
+
+ return 1;
+}
+
+/**
+ * Determine a new pivot point and modify the transformation matrix to
+ * match.
+ *
+ * For any given point q that is transformed by a 2D affine transformation
+ * matrix T about pivot point P the new point q' may be determined by the
+ * following equation:
+ *
+ * q' = T * (q - P) + P
+ *
+ * T and P are dependent, so we can modify one and find a new value for the
+ * other. We will label the original T and P as T0 and P0, and the new values
+ * will be labeled T1 and P1. We can find new values by solving the following
+ * equation:
+ *
+ * q' = T0 * (q - P0) + P0 = T1 * (q - P1) + P1
+ *
+ * In the calculations below, we use standard variables for the scalar values
+ * that make up T0 and P0:
+ *
+ * T0: [ a -b c0 ] P0: [ x0 ]
+ * [ b a d0 ] [ y0 ]
+ * [ 0 0 1 ] [ 0 ]
+ *
+ * Note that rotation and scaling are independent of the pivot point, so
+ * a0 == a1 and b0 == b1. Thus, the variable names are left as just a and b.
+ */
+static void set_pivot(struct grail_element *e, enum grail_pivot_type type)
+{
+ float *T = e->transform;
+ float a = T[0];
+ float b = T[3];
+ float c0 = T[2];
+ float d0 = T[5];
+ float x0 = e->pivot.x;
+ float y0 = e->pivot.y;
+ float x1;
+ float y1;
+
+ switch (type) {
+ case GRAIL_CENTROID:
+ /* Grail computation is performed on the centroid already. */
+ break;
+
+ case GRAIL_CENTER_OF_ROTATION:
+ /* If this fails, transformation is pure translation. We can't
+ * do anything in this case. */
+ if (center_of_rotation(a, b, c0, d0, x0, y0, &x1, &y1)) {
+ T[2] = T[5] = 0;
+ e->pivot.x = x1;
+ e->pivot.y = y1;
+ }
+ break;
+
+ /**
+ * We define an approximation of the convex hull of the touches as a
+ * circle centered at the centroid of the touch points and with a radius
+ * equal to the average distance of each touch point to the centroid. We
+ * then determine the pivot point within the circle that minimizes
+ * translation. To accomplish this, first determine the center of
+ * rotation point as above. Then check if it is within the confining
+ * circle. If it is, then stop. Otherwise, determine the intersection of
+ * the circle and the line defined by the centroid of the touch points
+ * and the center of rotation point. The intersection is the new pivot.
+ *
+ * Lastly, determine the new translation values c1 and d1 in the T1
+ * transformation matrix. To do this, we set P1 as:
+ *
+ * P1: [ x1 ]
+ * [ y1 ]
+ * [ 0 ]
+ *
+ * and then we solve the equation noted above for T1.
+ */
+ case GRAIL_CONVEX_HULL_RADIUS: {
+ float d2;
+ float scale;
+
+ /* If this fails, transformation is pure translation. We can't
+ * do anything in this case, and the pivot point will remain at
+ * the centroid which matches the criteria. */
+ if (!center_of_rotation(a, b, c0, d0, x0, y0, &x1, &y1))
+ break;
+
+ /* If the center of rotation falls within the circle, we've
+ * reached an optimal state. */
+ d2 = (x1 - x0)*(x1-x0) + (y1 - y0)*(y1-y0);
+ if (d2 <= e->radius2) {
+ T[2] = T[5] = 0;
+ e->pivot.x = x1;
+ e->pivot.y = y1;
+ break;
+ }
+
+ /* Intersect line from centroid to center of rotation to find
+ * the best pivot point. */
+ scale = sqrtf(e->radius2 / d2);
+ x1 = x0 + (x1 - x0) * scale;
+ y1 = y0 + (y1 - y0) * scale;
+
+ /* Compute the new translation values by solving the equation
+ * above. */
+ T[2] = a*(x1 - x0) + b*(y0 - y1) + c0 + x0 - x1;
+ T[5] = a*(y1 - y0) + b*(y1 - y0) + d0 + y0 - y1;
+ e->pivot.x = x1;
+ e->pivot.y = y1;
+ break;
+ }
+ }
+}
+
static void collect_transforms(struct grail_impl *impl,
struct grail_frame *frame,
const struct utouch_frame *touch)
@@ -326,22 +433,20 @@
if (!s->num_touches)
continue;
+ set_pivot(s, ctl->pivot_type);
+
dt = touch->time - s->start_time;
if (dt > ctl->glue_ms) {
unsigned int mask = s->active_mask;
- if (s->moveness > ctl->thresh_drag) {
- if (fabs(s->drag.x) > dx)
- mask |= GRAIL_EXPECT_X;
- if (fabs(s->drag.y) > dy)
- mask |= GRAIL_EXPECT_Y;
- }
- if (s->moveness < ctl->thresh_scale) {
- if (fabs(s->scale2 - 1) > ds2)
- mask |= GRAIL_EXPECT_SCALE;
- if (fabs(s->angle) > ctl->bar_angle)
- mask |= GRAIL_EXPECT_ANGLE;
- }
+ if (fabs(s->drag.x) > dx)
+ mask |= GRAIL_EXPECT_X;
+ if (fabs(s->drag.y) > dy)
+ mask |= GRAIL_EXPECT_Y;
+ if (fabs(s->scale2 - 1) > ds2)
+ mask |= GRAIL_EXPECT_SCALE;
+ if (fabs(s->angle) > ctl->bar_angle)
+ mask |= GRAIL_EXPECT_ANGLE;
s->active_mask = mask;
@@ -365,10 +470,16 @@
const struct utouch_frame *touch)
{
struct grail_impl *impl = ge->impl;
- struct grail_frame *frame = impl->frames[impl->nextframe];
- const struct grail_frame *prev = frame->prev;
+ struct grail_frame *frame;
+ const struct grail_frame *prev;
int i;
+ if (!impl->frames)
+ return 0;
+
+ frame = impl->frames[impl->nextframe];
+ prev = frame->prev;
+
if (touch->slot_revision == touch->prev->slot_revision &&
!prev->num_ongoing)
return 0;
=== removed file 'src/grail-gestures.c'
--- src/grail-gestures.c 2011-04-12 16:35:37 +0000
+++ src/grail-gestures.c 1970-01-01 00:00:00 +0000
@@ -1,210 +0,0 @@
-/*****************************************************************************
- *
- * grail - Gesture Recognition And Instantiation Library
- *
- * Copyright (C) 2010-2011 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 .
- *
- ****************************************************************************/
-
-#include "grail-recognizer.h"
-#include "grail-impl.h"
-#include
-
-static const float FM_SN[DIM_FM] = { 1000, 1000, 1000, 1000 };
-static const float FM_BAR[DIM_FM] = { 50, 50, 50, 50 };
-static const grail_time_t FM_HOLD_MS[DIM_FM] = { 60, 60, 60, 60 };
-static const grail_time_t FM_BAR_MS[DIM_FM] = { 300, 300, 500, 500 };
-static const grail_time_t SAMPLE_MS = 10;
-static const float EPS = 1e-3;
-
-static void compute_position(float *x, float *y,
- const struct utouch_frame *frame)
-{
- int i, n = frame->num_active;
- *x = 0;
- *y = 0;
- if (n < 1)
- return;
- for (i = 0; i < n; i++) {
- const struct utouch_contact *t = frame->active[i];
- *x += t->x;
- *y += t->y;
- }
- *x /= n;
- *y /= n;
-}
-
-static float compute_radius(float x, float y,
- const struct utouch_frame *frame)
-{
- int i, n = frame->num_active;
- float r = 0, r2 = 0;
- if (n < 2)
- return r;
- for (i = 0; i < n; i++) {
- const struct utouch_contact *t = frame->active[i];
- float dx = t->x - x;
- float dy = t->y - y;
- r2 += dx * dx + dy * dy;
- }
- r2 /= n;
- r = sqrt(r2);
- return r;
-}
-
-static float compute_rotation(float x, float y, float r,
- const struct utouch_frame *frame)
-{
- int i, n = frame->num_active;
- float da = 0, darc2 = 0;
- if (n < 2)
- return da;
- for (i = 0; i < n; i++) {
- const struct utouch_contact *t = frame->active[i];
- const struct utouch_contact *ot = t->prev;
- float dx = t->x - x;
- float dy = t->y - y;
- float mx = t->x - ot->x;
- float my = t->y - ot->y;
- darc2 += dx * my - dy * mx;
- }
- darc2 /= n;
- da = darc2 / (r * r);
- return da;
-}
-
-static void move_reset(struct move_model *m, int i, float x, grail_time_t t)
-{
- struct filter_model *fm = &m->fm[i];
- fm->raw_delta = 0;
- fm->action_delta = 0;
- fm->velocity = 0;
- fm->value = x;
- fm->original = x;
- fm->original_ms = t;
- fm->sample = x;
- fm->sample_ms = t;
- m->tickle &= ~(1 << i);
- m->active &= ~(1 << i);
- m->timeout &= ~(1 << i);
-}
-
-static void move_update(struct move_model *m, int i, float x, grail_time_t t)
-{
- struct filter_model *fm = &m->fm[i];
- float dt = t - fm->sample_ms;
- fm->raw_delta = x - fm->value;
- fm->action_delta = fm->raw_delta;
- fm->value = x;
- if (dt > SAMPLE_MS) {
- fm->velocity = (x - fm->sample) / dt;
- fm->sample = x;
- fm->sample_ms = t;
- }
- if (fabs(fm->raw_delta) > EPS)
- m->tickle |= (1 << i);
- else
- m->tickle &= ~(1 << i);
- if (m->active & (1 << i))
- return;
- fm->action_delta = 0;
- if (fabs(x - fm->original) > fm->bar) {
- if (t - fm->original_ms > fm->hold_ms) {
- m->active |= (1 << i);
- fm->action_delta = x - fm->original;
- }
- } else if (t - fm->original_ms > fm->bar_ms) {
- m->timeout |= (1 << i);
- }
-}
-
-void gru_init_motion(struct grail *ge)
-{
- struct utouch_surface *s = utouch_frame_get_surface(ge->impl->fh);
- struct gesture_recognizer *gru = ge->gru;
- struct move_model *m = &gru->move;
- float D[DIM_FM];
- int i;
- D[FM_X] = s->mapped_max_x - s->mapped_min_x;
- D[FM_Y] = s->mapped_max_y - s->mapped_min_y;
- D[FM_R] = sqrt(D[FM_X] * D[FM_X] + D[FM_Y] * D[FM_Y]);
- D[FM_A] = 2 * M_PI;
- for (i = 0; i < DIM_FM; i++) {
- m->fm[i].fuzz = D[i] / FM_SN[i];
- m->fm[i].bar = D[i] / FM_BAR[i];
- m->fm[i].hold_ms = FM_HOLD_MS[i];
- m->fm[i].bar_ms = FM_BAR_MS[i];
- }
-}
-
-void gru_motion(struct grail *ge,
- const struct utouch_frame *frame)
-{
- const struct utouch_surface *s = utouch_frame_get_surface(ge->impl->fh);
- struct gesture_recognizer *gru = ge->gru;
- struct move_model *m = &gru->move;
- grail_time_t t = frame->time;
- float x, y, r, a;
-
- compute_position(&x, &y, frame);
- if (frame->prev->revision != frame->revision) {
- r = compute_radius(x, y, frame);
- a = 0;
- move_reset(m, FM_X, x, t);
- move_reset(m, FM_Y, y, t);
- move_reset(m, FM_R, r, t);
- move_reset(m, FM_A, a, t);
- m->single = 0;
- m->multi = 0;
- } else if (frame->num_active < 2) {
- r = 0;
- a = 0;
- move_update(m, FM_X, x, t);
- move_update(m, FM_Y, y, t);
- move_reset(m, FM_R, r, t);
- move_reset(m, FM_A, a, t);
- m->single = 1;
- m->multi = 0;
- } else {
- r = compute_radius(x, y, frame);
- a = m->fm[FM_A].value;
- if (!s->is_semi_mt)
- a += compute_rotation(x, y, r, frame);
- move_update(m, FM_X, x, t);
- move_update(m, FM_Y, y, t);
- move_update(m, FM_R, r, t);
- move_update(m, FM_A, a, t);
- m->single = 0;
- m->multi = 1;
- }
- m->ntouch = frame->num_active;
- m->time = t;
-}
-
-void gru_event(struct grail *ge, int gid,
- const struct move_model *m,
- const grail_prop_t *prop, int nprop)
-{
- gin_gid_event(ge, gid, m->fm[FM_X].value, m->fm[FM_Y].value, m->ntouch,
- prop, nprop, 0);
-}
-
-void gru_end(struct grail *ge, int gid, const struct move_model *m,
- const grail_prop_t *prop, int nprop)
-{
- gin_gid_end(ge, gid, m->fm[FM_X].value, m->fm[FM_Y].value, m->ntouch,
- prop, nprop);
-}
=== removed file 'src/grail-gestures.h'
--- src/grail-gestures.h 2011-04-12 16:35:37 +0000
+++ src/grail-gestures.h 1970-01-01 00:00:00 +0000
@@ -1,115 +0,0 @@
-/*****************************************************************************
- *
- * grail - Gesture Recognition And Instantiation Library
- *
- * Copyright (C) 2010-2011 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 .
- *
- ****************************************************************************/
-
-#ifndef _GRAIL_GESTURES_H
-#define _GRAIL_GESTURES_H
-
-#include "grail-inserter.h"
-
-#define PRIO_POINTER 1
-#define PRIO_GESTURE 2
-#define PRIO_ENV 3
-#define PRIO_META 4
-#define PRIO_TAP 5
-
-#define DIM_FM 4
-
-#define FM_X 0
-#define FM_Y 1
-#define FM_R 2
-#define FM_A 3
-
-struct filter_model {
- float raw_delta;
- float action_delta;
- float velocity;
- float value;
- float original;
- float sample;
- float fuzz;
- float bar;
- grail_time_t original_ms;
- grail_time_t sample_ms;
- grail_time_t hold_ms;
- grail_time_t bar_ms;
-};
-
-struct move_model {
- struct filter_model fm[DIM_FM];
- int tickle, active, timeout;
- int single, multi, ntouch;
- grail_time_t time;
-};
-
-void gru_init_motion(struct grail *ge);
-void gru_motion(struct grail *ge,
- const struct utouch_frame *frame);
-void gru_event(struct grail *ge, int gid,
- const struct move_model *move,
- const grail_prop_t *prop, int nprop);
-void gru_end(struct grail *ge, int gid,
- const struct move_model *move,
- const grail_prop_t *prop, int nprop);
-
-struct combo_model {
- int active, gid;
- int mintouch, maxtouch;
- int nprop;
- grail_prop_t prop[DIM_GRAIL_PROP];
-};
-
-int gru_touch(struct grail *ge,
- const struct utouch_frame *frame);
-int gru_drag(struct grail *ge,
- const struct utouch_frame *frame);
-int gru_pinch(struct grail *ge,
- const struct utouch_frame *frame);
-int gru_rotate(struct grail *ge,
- const struct utouch_frame *frame);
-
-static inline int out_of_bounds(const struct combo_model *s,
- const struct move_model *m)
-{
- return m->ntouch < s->mintouch || m->ntouch > s->maxtouch;
-}
-
-int gru_wintouch(struct grail *ge,
- const struct utouch_frame *frame);
-int gru_windrag(struct grail *ge,
- const struct utouch_frame *frame);
-int gru_winpinch(struct grail *ge,
- const struct utouch_frame *frame);
-int gru_winrotate(struct grail *ge,
- const struct utouch_frame *frame);
-
-struct tapping_model {
- grail_time_t start;
- int mintouch, maxtouch;
- int active, gid, tap;
- int nprop;
- grail_prop_t prop[DIM_GRAIL_PROP];
-};
-
-int gru_tapping(struct grail *ge,
- const struct utouch_frame *frame);
-
-#endif
-
=== modified file 'src/grail-impl.h'
--- src/grail-impl.h 2011-04-12 16:35:37 +0000
+++ src/grail-impl.h 2011-04-27 19:43:23 +0000
@@ -82,6 +82,7 @@
unsigned int frame_size;
unsigned int slot_size;
struct grail_frame **frames;
+ const struct grail_frame *frame;
};
#endif
=== modified file 'src/grail-init.c'
--- src/grail-init.c 2011-04-12 16:35:37 +0000
+++ src/grail-init.c 2011-04-27 19:43:23 +0000
@@ -32,8 +32,6 @@
return 0;
c->glue_ms = 60;
- c->thresh_drag = 0.8;
- c->thresh_scale = 0.2;
c->bar_x = 0.03;
c->bar_y = 0.03;
c->bar_scale = 0.3;
=== modified file 'src/grail-inserter.c'
--- src/grail-inserter.c 2011-04-12 16:35:37 +0000
+++ src/grail-inserter.c 2011-04-27 19:43:23 +0000
@@ -37,18 +37,6 @@
return -1;
}
-static int mask_overlap(const grail_mask_t *a, const grail_mask_t *b,
- int bytes)
-{
- int i;
-
- for (i = 0; i < bytes; i++)
- if (a[i] & b[i])
- return 1;
-
- return 0;
-}
-
// todo: spanning tree for multi-user case
static void setup_new_gestures(struct grail *ge,
const struct utouch_frame *frame)
@@ -157,15 +145,6 @@
grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
struct slot_state *s = &gin->state[i];
- if (!s->timeout)
- continue;
- if (mask_overlap(keep, s->span, sizeof(keep)))
- continue;
- gin_gid_discard(ge, s->id);
- }
-
- grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
- struct slot_state *s = &gin->state[i];
struct gesture_event ev;
grail_mask_set(gin->types, s->type);
if (s->priority < hold[s->slice] && !s->sent)
@@ -202,7 +181,6 @@
s->priority = priority;
s->slice = 0;
}
- s->timeout = 0;
s->sent = 0;
s->id = gin->gestureid++ & MAX_GESTURE_ID;
s->status = GRAIL_STATUS_BEGIN;
@@ -230,13 +208,6 @@
grail_mask_set(gin->unused, i);
}
-void gin_gid_timeout(struct grail *ge, int gid)
-{
- int i = find_gslot(ge->gin, gid);
- if (i >= 0)
- ge->gin->state[i].timeout = 1;
-}
-
void gin_gid_event(struct grail *ge, int gid,
float x, float y, int ntouch,
const grail_prop_t *prop, int nprop,
@@ -297,7 +268,4 @@
s->mapped_min_y = tmin->y;
s->mapped_max_x = tmax->x;
s->mapped_max_y = tmax->y;
-
- if (ge->gru)
- gru_init_motion(ge);
}
=== modified file 'src/grail-inserter.h'
--- src/grail-inserter.h 2011-04-12 16:35:37 +0000
+++ src/grail-inserter.h 2011-04-27 19:43:23 +0000
@@ -37,7 +37,6 @@
int type;
int priority;
int slice;
- int timeout;
int sent;
int id;
int status;
@@ -80,7 +79,6 @@
int gin_gid_begin(struct grail *ge, int type, int priority,
const struct utouch_frame *frame);
void gin_gid_discard(struct grail *ge, int gid);
-void gin_gid_timeout(struct grail *ge, int gid);
void gin_gid_event(struct grail *ge, int gid,
float x, float y, int ntouch,
=== modified file 'src/grail-legacy.c'
--- src/grail-legacy.c 2011-04-12 16:35:37 +0000
+++ src/grail-legacy.c 2011-04-27 19:43:23 +0000
@@ -31,6 +31,110 @@
#ifndef GRAIL_NO_LEGACY_ABI
+#define DIM_FRAMES 100
+#define FRAME_RATE 100
+
+int grail_open(struct grail *ge, int fd)
+{
+ struct grail_impl *x;
+ struct stat fs;
+ int ret;
+
+ ret = fstat(fd, &fs);
+ if (ret)
+ return ret;
+
+ x = calloc(1, sizeof(*x));
+ if (!x)
+ return -ENOMEM;
+
+ if (!fs.st_rdev)
+ x->fptest = fdopen(fd, "r");
+
+ x->evemu = evemu_new(x->fptest ? "fptest" : 0);
+ if (!x->evemu) {
+ ret = -ENOMEM;
+ goto freemem;
+ }
+ if (x->fptest)
+ ret = evemu_read(x->evemu, x->fptest) <= 0;
+ else
+ ret = evemu_extract(x->evemu, fd);
+ if (ret)
+ goto freemem;
+ if (!utouch_frame_is_supported_mtdev(x->evemu)) {
+ ret = -ENODEV;
+ goto freemem;
+ }
+
+ if (!x->fptest) {
+ x->mtdev = mtdev_new_open(fd);
+ if (!x->mtdev) {
+ ret = -ENOMEM;
+ goto freemem;
+ }
+ }
+ x->fh = utouch_frame_new_engine(DIM_FRAMES, DIM_TOUCH, FRAME_RATE);
+ if (!x->fh) {
+ ret = -ENOMEM;
+ goto freedev;
+ }
+ ret = utouch_frame_init_mtdev(x->fh, x->evemu);
+ if (ret)
+ goto freeframe;
+
+ ret = create_grail2(x, x->fh, DIM_FRAMES, NULL,
+ GRAIL_VERSION,
+ sizeof(struct grail_control),
+ sizeof(struct grail_frame),
+ sizeof(struct grail_element));
+ if (ret)
+ goto freeframe;
+
+ ge->impl = x;
+
+ ret = gin_init(ge);
+ if (ret)
+ goto freegrail2;
+
+ ret = gru_init(ge);
+ if (ret)
+ goto freegin;
+
+ return 0;
+ freegin:
+ gin_destroy(ge);
+ freegrail2:
+ destroy_grail2(x);
+ freeframe:
+ utouch_frame_delete_engine(x->fh);
+ freedev:
+ if (x->mtdev)
+ mtdev_close_delete(x->mtdev);
+ freemem:
+ evemu_delete(x->evemu);
+ if (x->fptest)
+ fclose(x->fptest);
+ free(x);
+ ge->impl = 0;
+ return ret;
+}
+
+void grail_close(struct grail *ge, int fd)
+{
+ struct grail_impl *x = ge->impl;
+ gru_destroy(ge);
+ gin_destroy(ge);
+ destroy_grail2(x);
+ utouch_frame_delete_engine(x->fh);
+ if (x->mtdev)
+ mtdev_close_delete(x->mtdev);
+ evemu_delete(x->evemu);
+ if (x->fptest)
+ fclose(x->fptest);
+ free(x);
+ ge->impl = 0;
+}
void grail_filter_abs_events(struct grail *ge, int usage)
{
struct grail_impl *x = ge->impl;
=== modified file 'src/grail-recognizer.c'
--- src/grail-recognizer.c 2011-04-12 16:35:37 +0000
+++ src/grail-recognizer.c 2011-04-27 19:43:23 +0000
@@ -23,6 +23,178 @@
#include
#include
#include
+#include
+
+static const float TAP_TIME_MS = 300;
+static const int MAX_TOUCH_GESTURE = 5;
+
+static void touch_props(const struct gesture_inserter *gin,
+ struct combo_model *s, const struct grail_element *m,
+ const struct utouch_frame *frame)
+{
+ s->nprop = 0;
+}
+
+static void drag_props(const struct gesture_inserter *gin,
+ struct combo_model *s, const struct grail_element *m,
+ const struct utouch_frame *frame)
+{
+ s->prop[GRAIL_PROP_DRAG_DX] = m->drag.x - m->prev->drag.x;
+ s->prop[GRAIL_PROP_DRAG_DY] = m->drag.y - m->prev->drag.y;
+ s->prop[GRAIL_PROP_DRAG_VX] = m->velocity.x;
+ s->prop[GRAIL_PROP_DRAG_VY] = m->velocity.y;
+ s->prop[GRAIL_PROP_DRAG_X] = m->drag.x;
+ s->prop[GRAIL_PROP_DRAG_Y] = m->drag.y;
+ s->nprop = 6;
+}
+
+static void pinch_props(const struct gesture_inserter *gin,
+ struct combo_model *s, const struct grail_element *m,
+ const struct utouch_frame *frame)
+{
+ s->prop[GRAIL_PROP_PINCH_DR] =
+ sqrt(m->radius2) - sqrt(m->prev->radius2);
+ s->prop[GRAIL_PROP_PINCH_VR] = 0;
+ s->prop[GRAIL_PROP_PINCH_R] = sqrt(m->radius2);
+ s->nprop = 3;
+}
+
+static void rotate_props(const struct gesture_inserter *gin,
+ struct combo_model *s, const struct grail_element *m,
+ const struct utouch_frame *frame)
+{
+ s->prop[GRAIL_PROP_ROTATE_DA] = m->angle - m->prev->angle;
+ s->prop[GRAIL_PROP_ROTATE_VA] = 0;
+ s->prop[GRAIL_PROP_ROTATE_A] = m->angle;
+ s->nprop = 3;
+}
+
+static void tap_props(const struct gesture_inserter *gin,
+ struct combo_model *s, const struct grail_element *m,
+ const struct utouch_frame *frame)
+{
+ s->prop[GRAIL_PROP_TAP_DT] = frame->time - s->start;
+ s->prop[GRAIL_PROP_TAP_X] = m->center.x;
+ s->prop[GRAIL_PROP_TAP_Y] = m->center.y;
+ s->nprop = 3;
+}
+
+static const struct gesture_handler touch_handler = {
+ GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
+ {
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_TOUCH1, 1, 1, PRIO_GESTURE },
+ { GRAIL_TYPE_TOUCH2, 2, 2, PRIO_GESTURE },
+ { GRAIL_TYPE_TOUCH3, 3, 3, PRIO_GESTURE },
+ { GRAIL_TYPE_TOUCH4, 4, 4, PRIO_GESTURE },
+ { GRAIL_TYPE_TOUCH5, 5, 5, PRIO_GESTURE }
+ },
+ touch_props
+};
+
+static const struct gesture_handler drag_handler = {
+ GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
+ {
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_DRAG1, 1, 1, PRIO_GESTURE },
+ { GRAIL_TYPE_DRAG2, 2, 2, PRIO_GESTURE },
+ { GRAIL_TYPE_DRAG3, 3, 3, PRIO_GESTURE },
+ { GRAIL_TYPE_DRAG4, 4, 4, PRIO_GESTURE },
+ { GRAIL_TYPE_DRAG5, 5, 5, PRIO_GESTURE }
+ },
+ drag_props
+};
+
+static const struct gesture_handler pinch_handler = {
+ GRAIL_EXPECT_SCALE,
+ {
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_PINCH2, 2, 2, PRIO_GESTURE },
+ { GRAIL_TYPE_PINCH3, 3, 3, PRIO_GESTURE },
+ { GRAIL_TYPE_PINCH4, 4, 4, PRIO_GESTURE },
+ { GRAIL_TYPE_PINCH5, 5, 5, PRIO_GESTURE }
+ },
+ pinch_props
+};
+
+static const struct gesture_handler rotate_handler = {
+ GRAIL_EXPECT_ANGLE,
+ {
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_ROTATE2, 2, 2, PRIO_GESTURE },
+ { GRAIL_TYPE_ROTATE3, 3, 3, PRIO_GESTURE },
+ { GRAIL_TYPE_ROTATE4, 4, 4, PRIO_GESTURE },
+ { GRAIL_TYPE_ROTATE5, 5, 5, PRIO_GESTURE }
+ },
+ rotate_props
+};
+
+static const struct gesture_handler tap_handler = {
+ GRAIL_EXPECT_MASK,
+ {
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_TAP1, 1, 1, PRIO_TAP },
+ { GRAIL_TYPE_TAP2, 2, 2, PRIO_TAP },
+ { GRAIL_TYPE_TAP3, 3, 3, PRIO_TAP },
+ { GRAIL_TYPE_TAP4, 4, 4, PRIO_TAP },
+ { GRAIL_TYPE_TAP5, 5, 5, PRIO_TAP }
+ },
+ tap_props
+};
+
+static const struct gesture_handler wintouch_handler = {
+ GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
+ {
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_ETOUCH, 1, 3, PRIO_ENV },
+ { GRAIL_TYPE_MTOUCH, 1, 4, PRIO_META },
+ { -1, 0, 0, 0 },
+ },
+ touch_props
+};
+
+static const struct gesture_handler windrag_handler = {
+ GRAIL_EXPECT_X | GRAIL_EXPECT_Y,
+ {
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_EDRAG, 1, 3, PRIO_ENV },
+ { GRAIL_TYPE_MDRAG, 1, 4, PRIO_META },
+ { -1, 0, 0, 0 },
+ },
+ drag_props
+};
+
+static const struct gesture_handler winpinch_handler = {
+ GRAIL_EXPECT_SCALE,
+ {
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_EPINCH, 2, 3, PRIO_ENV },
+ { GRAIL_TYPE_MPINCH, 2, 4, PRIO_META },
+ { -1, 0, 0, 0 },
+ },
+ pinch_props
+};
+
+static const struct gesture_handler winrotate_handler = {
+ GRAIL_EXPECT_ANGLE,
+ {
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { -1, 0, 0, 0 },
+ { GRAIL_TYPE_EROTATE, 2, 3, PRIO_ENV },
+ { GRAIL_TYPE_MROTATE, 2, 4, PRIO_META },
+ { -1, 0, 0, 0 },
+ },
+ rotate_props
+};
int gru_init(struct grail *ge)
{
@@ -30,8 +202,18 @@
gru = calloc(1, sizeof(struct gesture_recognizer));
if (!gru)
return -ENOMEM;
+
+ gru->touch.handler = &touch_handler;
+ gru->drag.handler = &drag_handler;
+ gru->pinch.handler = &pinch_handler;
+ gru->rotate.handler = &rotate_handler;
+ gru->tapping.handler = &tap_handler;
+ gru->wintouch.handler = &wintouch_handler;
+ gru->windrag.handler = &windrag_handler;
+ gru->winpinch.handler = &winpinch_handler;
+ gru->winrotate.handler = &winrotate_handler;
+
ge->gru = gru;
- gru_init_motion(ge);
return 0;
}
@@ -41,18 +223,173 @@
ge->gru = NULL;
}
-void gru_recognize(struct grail *ge, const struct utouch_frame *frame)
-{
- if (!ge->gin || !ge->gru)
- return;
- gru_motion(ge, frame);
- gru_touch(ge, frame);
- gru_drag(ge, frame);
- gru_pinch(ge, frame);
- gru_rotate(ge, frame);
- gru_wintouch(ge, frame);
- gru_windrag(ge, frame);
- gru_winpinch(ge, frame);
- gru_winrotate(ge, frame);
- gru_tapping(ge, frame);
-}
+static void set_props(struct grail *ge,
+ struct combo_model *s,
+ const struct utouch_frame *frame)
+{
+ const struct gesture_handler *gh = s->handler;
+ gh->set_props(ge->gin, s, ge->gru->move, frame);
+ s->nprop += gin_add_contact_props(ge->gin, s->prop + s->nprop, frame);
+}
+
+static int gru_touch_handler(struct grail *ge,
+ struct combo_model *state,
+ const struct utouch_frame *frame)
+{
+ struct gesture_recognizer *gru = ge->gru;
+ struct gesture_inserter *gin = ge->gin;
+ struct grail_element *move = gru->move;
+ const struct gesture_handler *gh = state->handler;
+ int ntouch = move->num_touches;
+ if (frame->slot_revision != frame->prev->slot_revision) {
+ if (state->active) {
+ gin_gid_end(ge, state->gid, move->center.x,
+ move->center.y, ntouch,
+ state->prop, state->nprop);
+ state->active = 0;
+ }
+ }
+ if (ntouch > MAX_TOUCH_GESTURE)
+ return 0;
+ if (!state->active) {
+ struct gesture_head h = gh->getype[ntouch];
+ if (h.type < 0)
+ return 0;
+ state->gid = gin_gid_begin(ge, h.type, -h.priority, frame);
+ state->mintouch = h.mintouch;
+ state->maxtouch = h.maxtouch;
+ state->active = 1;
+ }
+ set_props(ge, state, frame);
+ gin_gid_event(ge, state->gid, move->center.x, move->center.y,
+ ntouch, state->prop, state->nprop, 0);
+ return 1;
+}
+
+static int gru_gesture_handler(struct grail *ge,
+ struct combo_model *state,
+ const struct utouch_frame *frame)
+{
+ struct gesture_recognizer *gru = ge->gru;
+ struct gesture_inserter *gin = ge->gin;
+ struct grail_element *move = gru->move;
+ const struct gesture_handler *gh = state->handler;
+ int expect = move->expect_mask & gh->fm_mask;
+ int active = move->active_mask & gh->fm_mask;
+ int ntouch = move->num_touches;
+ if (state->active &&
+ (!expect || ntouch < state->mintouch || ntouch > state->maxtouch)) {
+ gin_gid_end(ge, state->gid, move->center.x,
+ move->center.y,ntouch,
+ state->prop, state->nprop);
+ state->active = 0;
+ return 0;
+ }
+ if (!expect || !active || ntouch > MAX_TOUCH_GESTURE)
+ return 0;
+ if (!state->active) {
+ struct gesture_head h = gh->getype[ntouch];
+ if (h.type < 0)
+ return 0;
+ state->gid = gin_gid_begin(ge, h.type, h.priority, frame);
+ state->mintouch = h.mintouch;
+ state->maxtouch = h.maxtouch;
+ state->active = 1;
+ }
+ set_props(ge, state, frame);
+ gin_gid_event(ge, state->gid, move->center.x, move->center.y,
+ ntouch, state->prop, state->nprop, 0);
+ return 1;
+}
+
+static int gru_tap_handler(struct grail *ge,
+ struct combo_model *state,
+ const struct utouch_frame *frame)
+{
+ struct gesture_recognizer *gru = ge->gru;
+ struct grail_element *move = gru->move;
+ const struct gesture_handler *gh = state->handler;
+ int active = move->active_mask & gh->fm_mask;
+ int ntouch = move->num_touches;
+ state->tap = 0;
+ if (frame->num_active && !frame->prev->num_active) {
+ state->mintouch = 0;
+ state->maxtouch = 0;
+ }
+ if (ntouch > state->maxtouch) {
+ if (state->active) {
+ gin_gid_discard(ge, state->gid);
+ state->active = 0;
+ }
+ state->start = frame->time;
+ state->maxtouch = ntouch;
+ set_props(ge, state, frame);
+ if (state->maxtouch <= MAX_TOUCH_GESTURE) {
+ struct gesture_head h = gh->getype[ntouch];
+ if (h.type < 0)
+ return 0;
+ state->gid = gin_gid_begin(ge, h.type, h.priority,
+ frame);
+ state->active = 1;
+ }
+ return 0;
+ }
+ if (!state->active) {
+ state->mintouch = ntouch;
+ state->maxtouch = ntouch;
+ return 0;
+ }
+ if (ntouch <= state->mintouch) {
+ int x = state->prop[GRAIL_PROP_TAP_X];
+ int y = state->prop[GRAIL_PROP_TAP_Y];
+ int t = frame->time - state->start;
+ if (t > TAP_TIME_MS) {
+ gin_gid_discard(ge, state->gid);
+ state->mintouch = ntouch;
+ state->maxtouch = ntouch;
+ state->active = 0;
+ return 0;
+ }
+ state->tap = state->maxtouch;
+ state->prop[GRAIL_PROP_TAP_DT] = t;
+ gin_gid_event(ge, state->gid, x, y, state->maxtouch,
+ state->prop, state->nprop, 1);
+ state->mintouch = ntouch;
+ state->maxtouch = ntouch;
+ state->active = 0;
+ return 1;
+ }
+ if (!ntouch)
+ return 0;
+ state->prop[GRAIL_PROP_TAP_DT] = frame->time - state->start;
+ if (active || frame->time - state->start > TAP_TIME_MS) {
+ gin_gid_discard(ge, state->gid);
+ state->mintouch = ntouch;
+ state->maxtouch = ntouch;
+ state->active = 0;
+ }
+ return 0;
+}
+
+void gru_recognize(struct grail *ge,
+ const struct grail_frame *frame,
+ const struct utouch_frame *touch)
+{
+ struct gesture_recognizer *gru = ge->gru;
+
+ if (frame && frame->num_ongoing)
+ gru->slot = frame->ongoing[frame->num_ongoing - 1]->slot;
+
+ gru->move = frame->slots[gru->slot];
+
+ gru_touch_handler(ge, &gru->touch, touch);
+ gru_gesture_handler(ge, &gru->drag, touch);
+ gru_gesture_handler(ge, &gru->pinch, touch);
+ gru_gesture_handler(ge, &gru->rotate, touch);
+ gru_touch_handler(ge, &gru->wintouch, touch);
+ gru_gesture_handler(ge, &gru->windrag, touch);
+ gru_gesture_handler(ge, &gru->winpinch, touch);
+ gru_gesture_handler(ge, &gru->winrotate, touch);
+ gru_tap_handler(ge, &gru->tapping, touch);
+}
+
=== modified file 'src/grail-recognizer.h'
--- src/grail-recognizer.h 2011-04-12 16:35:37 +0000
+++ src/grail-recognizer.h 2011-04-27 19:43:23 +0000
@@ -22,10 +22,26 @@
#ifndef _GRAIL_RECOGNIZER_H
#define _GRAIL_RECOGNIZER_H
-#include "grail-gestures.h"
+#include "grail-inserter.h"
+
+#define PRIO_POINTER 1
+#define PRIO_GESTURE 2
+#define PRIO_ENV 3
+#define PRIO_META 4
+#define PRIO_TAP 5
+
+struct combo_model {
+ grail_time_t start;
+ int active, gid, tap;
+ int mintouch, maxtouch;
+ int nprop;
+ grail_prop_t prop[DIM_GRAIL_PROP];
+ const struct gesture_handler *handler;
+};
struct gesture_recognizer {
- struct move_model move;
+ int slot;
+ struct grail_element *move;
struct combo_model touch;
struct combo_model drag;
struct combo_model pinch;
@@ -34,11 +50,30 @@
struct combo_model windrag;
struct combo_model winpinch;
struct combo_model winrotate;
- struct tapping_model tapping;
+ struct combo_model tapping;
+};
+
+struct gesture_head {
+ int type;
+ int mintouch;
+ int maxtouch;
+ int priority;
+};
+
+struct gesture_handler {
+ int fm_mask;
+ struct gesture_head getype[DIM_TOUCH + 1];
+
+ void (*set_props)(const struct gesture_inserter *gin,
+ struct combo_model *state,
+ const struct grail_element *element,
+ const struct utouch_frame *frame);
};
int gru_init(struct grail *ge);
-void gru_recognize(struct grail *ge, const struct utouch_frame *frame);
+void gru_recognize(struct grail *ge,
+ const struct grail_frame *frame,
+ const struct utouch_frame *touch);
void gru_destroy(struct grail *ge);
#endif
=== modified file 'tools/grail-test-mtdev.c'
--- tools/grail-test-mtdev.c 2011-04-12 16:35:37 +0000
+++ tools/grail-test-mtdev.c 2011-04-27 19:43:23 +0000
@@ -120,7 +120,6 @@
slot->transform[4], slot->transform[5],
slot->transform[6], slot->transform[7],
slot->transform[8]);
- fprintf(stderr, " moveness: %f\n", slot->moveness);
fprintf(stderr, " pivot.x: %f\n", slot->pivot.x);
fprintf(stderr, " pivot.y: %f\n", slot->pivot.y);
fprintf(stderr, " drag.x: %f\n", slot->drag.x);
=== modified file 'tools/grail-transform.c'
--- tools/grail-transform.c 2011-04-12 16:35:37 +0000
+++ tools/grail-transform.c 2011-04-27 19:43:23 +0000
@@ -53,6 +53,7 @@
int screen;
float off_x, off_y;
unsigned long white, black;
+ XColor red;
};
static void clear_screen(struct appdata *w)
@@ -77,29 +78,29 @@
static void draw_object(struct appdata *w)
{
- static const double frac = 0.01;
+ static const double frac = 0.04;
const struct utouch_surface *s = utouch_frame_get_surface(w->fh);
double d = frac * (s->mapped_max_x - s->mapped_min_x);
int i;
+ XSetForeground(w->dsp, w->gc, w->black);
XDrawLines(w->dsp, w->win, w->gc, w->pts, 5, CoordModeOrigin);
- if (w->scaling)
- XFillArc(w->dsp, w->win, w->gc,
- w->pivot.x - d / 2, w->pivot.y - d / 2,
- d, d, 0, 360 * 64);
-
- d *= 4;
for (i = 0; i < w->ntouch; i++)
XFillArc(w->dsp, w->win, w->gc,
w->touch[i].x - d / 2, w->touch[i].y - d / 2,
d, d, 0, 360 * 64);
+
+ d /= 4;
+ XSetForeground(w->dsp, w->gc, w->red.pixel);
+ XFillArc(w->dsp, w->win, w->gc,
+ w->pivot.x - d / 2, w->pivot.y - d / 2,
+ d, d, 0, 360 * 64);
}
static void report_frame(struct appdata *w,
const struct utouch_frame *touch)
{
- const struct grail_control *ctl = grail_get_control(w->ge);
const struct grail_frame *frame;
const struct grail_element *slot;
struct grail_coord tmp;
@@ -121,8 +122,7 @@
w->pos[i] = tmp;
}
- XSetForeground(w->dsp, w->gc, w->white);
- draw_object(w);
+ clear_screen(w);
w->ntouch = touch->num_active;
for (i = 0; i < w->ntouch; i++) {
@@ -130,7 +130,6 @@
w->touch[i].y = touch->active[i]->y - w->off_y;
}
- w->scaling = slot->moveness < ctl->thresh_scale;
w->pivot.x = slot->pivot.x - w->off_x;
w->pivot.y = slot->pivot.y - w->off_y;
@@ -148,6 +147,7 @@
static int init_window(struct appdata *w)
{
int event, err;
+ Colormap colormap;
w->pos[0].x = 100;
w->pos[0].y = 100;
@@ -169,6 +169,9 @@
w->white = WhitePixel(w->dsp, w->screen);
w->black = BlackPixel(w->dsp, w->screen);
+ colormap = DefaultColormap(w->dsp, w->screen);
+ XAllocNamedColor(w->dsp, colormap, "red", &w->red, &w->red);
+
w->win = XCreateSimpleWindow(w->dsp, XDefaultRootWindow(w->dsp),
0, 0, 600, 600, 0, w->black, w->white);
w->gc = DefaultGC(w->dsp, w->screen);
@@ -260,6 +263,7 @@
grail_get_control(w->ge)->drop_y_ms = 1e8;
grail_get_control(w->ge)->drop_scale_ms = 1e8;
grail_get_control(w->ge)->drop_angle_ms = 1e8;
+ grail_get_control(w->ge)->pivot_type = GRAIL_CONVEX_HULL_RADIUS;
loop_device_mtdev(w);
@@ -329,6 +333,8 @@
if (!w->ge)
return -1;
+ grail_get_control(w->ge)->pivot_type = GRAIL_CONVEX_HULL_RADIUS;
+
loop_device_xi2(w, id);
grail_delete(w->ge);
=== modified file 'utouch-grail.sym.in'
--- utouch-grail.sym.in 2011-04-12 16:35:23 +0000
+++ utouch-grail.sym.in 2011-04-27 19:43:23 +0000
@@ -4,6 +4,7 @@
grail_get_contact_frame
grail_get_contacts
grail_get_control
+grail_get_gesture_frame
grail_get_units
grail_get_version
grail_idle
@@ -11,6 +12,7 @@
grail_mask_count
grail_mask_get_first
grail_mask_get_next
+grail_mask_inner
grail_mask_set_mask
grail_new_raw
grail_open