summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/grail.h21
-rw-r--r--src/Makefile.am5
-rw-r--r--src/gestures-combo.c66
-rw-r--r--src/gestures-pan.c (renamed from src/gestures-zoom.c)58
-rw-r--r--src/gestures-pinch.c (renamed from src/gestures-scroll.c)61
-rw-r--r--src/gestures-rotate.c52
-rw-r--r--src/gestures-tapping.c96
-rw-r--r--src/grail-gestures.c128
-rw-r--r--src/grail-gestures.h68
-rw-r--r--src/grail-inserter.c107
-rw-r--r--src/grail-inserter.h27
-rw-r--r--src/grail-recognizer.c29
-rw-r--r--src/grail-recognizer.h7
-rw-r--r--test/grail.c28
-rw-r--r--test/touch.c3
15 files changed, 440 insertions, 316 deletions
diff --git a/include/grail.h b/include/grail.h
index 0570101..1adeda2 100644
--- a/include/grail.h
+++ b/include/grail.h
@@ -34,11 +34,22 @@
34#define DIM_GRAIL_PROP 16 34#define DIM_GRAIL_PROP 16
35#define DIM_GRAIL_PROP_BYTES ((DIM_GRAIL_PROP + 7) >> 3) 35#define DIM_GRAIL_PROP_BYTES ((DIM_GRAIL_PROP + 7) >> 3)
36 36
37#define GRAIL_TYPE_MOVE 0 37#define GRAIL_TYPE_MOVE 0 /* reserved */
38#define GRAIL_TYPE_SCROLL 1 38
39#define GRAIL_TYPE_ZOOM 2 39#define GRAIL_TYPE_PAN 1 /* two-finger pan/scroll */
40#define GRAIL_TYPE_ROTATE 3 40#define GRAIL_TYPE_PINCH 2 /* two-finger pinch-to-zoom */
41#define GRAIL_TYPE_SZRCOMBO 4 41#define GRAIL_TYPE_ROTATE 3 /* two-finger rotation */
42#define GRAIL_TYPE_COMBO2 4 /* two-finger combo */
43#define GRAIL_TYPE_SWIPE 5 /* three-finger pan */
44#define GRAIL_TYPE_SCALE 6 /* three-finger pinch */
45#define GRAIL_TYPE_TURN 7 /* three-finger rotate */
46#define GRAIL_TYPE_COMBO3 8 /* three-finger combo */
47
48#define GRAIL_TYPE_TAP1 9 /* single one-finger tap */
49#define GRAIL_TYPE_TAP2 10 /* single two-finger tap */
50#define GRAIL_TYPE_TAP3 11 /* single three-finger tap */
51#define GRAIL_TYPE_TAP4 12 /* single four-finger tap */
52#define GRAIL_TYPE_TAP5 13 /* single five-finger tap */
42 53
43#define GRAIL_STATUS_BEGIN 0 54#define GRAIL_STATUS_BEGIN 0
44#define GRAIL_STATUS_UPDATE 1 55#define GRAIL_STATUS_UPDATE 1
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 = \
10 grail-bits.c \ 10 grail-bits.c \
11 grail-inserter.c \ 11 grail-inserter.c \
12 grail-gestures.c \ 12 grail-gestures.c \
13 gestures-scroll.c \ 13 gestures-pan.c \
14 gestures-zoom.c \ 14 gestures-pinch.c \
15 gestures-rotate.c \ 15 gestures-rotate.c \
16 gestures-combo.c \ 16 gestures-combo.c \
17 gestures-tapping.c \
17 grail-recognizer.c \ 18 grail-recognizer.c \
18 grail-api.c 19 grail-api.c
19 20
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 @@
26#include <math.h> 26#include <math.h>
27#include <stdio.h> 27#include <stdio.h>
28 28
29void gru_reset_combo(struct grail *ge,
30 const struct touch_frame *frame)
31{
32 struct gesture_inserter *gin = ge->gin;
33 struct gesture_recognizer *gru = ge->gru;
34 struct combo_model *state = &gru->combo;
35 struct move_model *move = &gru->move;
36 gin_gesture_discard_type(gin, GRAIL_TYPE_SZRCOMBO);
37 state->r = move->r;
38 state->active = 0;
39 state->running = 0;
40}
41
42int gru_combo(struct grail *ge, 29int gru_combo(struct grail *ge,
43 const struct touch_frame *frame) 30 const struct touch_frame *frame)
44{ 31{
45 struct gesture_inserter *gin = ge->gin;
46 struct gesture_recognizer *gru = ge->gru; 32 struct gesture_recognizer *gru = ge->gru;
47 struct combo_model *state = &gru->combo; 33 struct combo_model *state = &gru->combo;
48 struct move_model *move = &gru->move; 34 struct move_model *move = &gru->move;
49 grail_prop_t prop[DIM_GRAIL_PROP]; 35 grail_prop_t prop[DIM_GRAIL_PROP];
50 float dx, dy, dr, da; 36 if (!move->motion) {
51 int i; 37 if (state->active) {
52 dx = move->x - state->x; 38 gru_end(ge, state->gid, move);
53 dy = move->y - state->y; 39 state->active = 0;
54 dr = move->r - state->r; 40 }
55 da = move->a - state->a; 41 return 0;
56 if (fabs(dx) < 1 && fabs(dy) < 1 && fabs(da) < 1 && fabs(dr) < 1) 42 }
43 if (!move->x.tickle && !move->y.tickle &&
44 !move->r.tickle && !move->a.tickle)
57 return 0; 45 return 0;
58 if (!state->active) { 46 if (!state->active) {
59 i = gin_gesture_begin(ge, 47 switch(move->ntouch) {
60 GRAIL_TYPE_SZRCOMBO, 2, 48 case 2:
61 frame->touches, sizeof(frame->touches)); 49 state->gid = gin_gid_begin(ge, GRAIL_TYPE_COMBO2, frame);
62 state->geslot = i; 50 break;
51 case 3:
52 state->gid = gin_gid_begin(ge, GRAIL_TYPE_COMBO3, frame);
53 break;
54 default:
55 return 0;
56 }
63 state->active = 1; 57 state->active = 1;
64 } 58 }
65 if (!state->running && 59 if (!move->x.active && !move->y.active &&
66 fabs(dx) < move->xbar && fabs(dy) < move->ybar && 60 !move->r.active && !move->a.active)
67 fabs(da) < move->abar && fabs(dr) < move->rbar)
68 return 0; 61 return 0;
69 state->running = 1; 62 prop[0] = move->x.active ? move->x.delta : 0;
70 prop[0] = dx; 63 prop[1] = move->y.active ? move->y.delta : 0;
71 prop[1] = dy; 64 prop[2] = move->r.active ? move->r.delta : 0;
72 prop[2] = dr; 65 prop[3] = move->a.active ? move->a.delta : 0;
73 prop[3] = da; 66 gru_event(ge, state->gid, move, prop, 4);
74 gin_gesture_event(gin, state->geslot,
75 move->x, move->y, move->ntouch,
76 prop, 4);
77 state->x = move->x;
78 state->y = move->y;
79 state->r = move->r;
80 state->a = move->a;
81 return 1; 67 return 1;
82} 68}
diff --git a/src/gestures-zoom.c b/src/gestures-pan.c
index 9e05b8b..541c502 100644
--- a/src/gestures-zoom.c
+++ b/src/gestures-pan.c
@@ -26,46 +26,40 @@
26#include <math.h> 26#include <math.h>
27#include <stdio.h> 27#include <stdio.h>
28 28
29void gru_reset_zoom(struct grail *ge, 29int gru_pan(struct grail *ge,
30 const struct touch_frame *frame) 30 const struct touch_frame *frame)
31{ 31{
32 struct gesture_inserter *gin = ge->gin;
33 struct gesture_recognizer *gru = ge->gru; 32 struct gesture_recognizer *gru = ge->gru;
34 struct zoom_model *state = &gru->zoom; 33 struct combo_model *state = &gru->pan;
35 struct move_model *move = &gru->move;
36 gin_gesture_discard_type(gin, GRAIL_TYPE_ZOOM);
37 state->r = move->r;
38 state->active = 0;
39 state->zooming = 0;
40}
41
42int gru_zoom(struct grail *ge,
43 const struct touch_frame *frame)
44{
45 struct gesture_inserter *gin = ge->gin;
46 struct gesture_recognizer *gru = ge->gru;
47 struct zoom_model *state = &gru->zoom;
48 struct move_model *move = &gru->move; 34 struct move_model *move = &gru->move;
49 grail_prop_t prop[DIM_GRAIL_PROP]; 35 grail_prop_t prop[DIM_GRAIL_PROP];
50 float dr; 36 if (!move->motion) {
51 int i; 37 if (state->active) {
52 dr = move->r - state->r; 38 gru_end(ge, state->gid, move);
53 if (fabs(dr) < 1) 39 state->active = 0;
40 }
41 return 0;
42 }
43 if (!move->x.tickle && !move->y.tickle)
54 return 0; 44 return 0;
55 if (!state->active) { 45 if (!state->active) {
56 i = gin_gesture_begin(ge, 46 switch(move->ntouch) {
57 GRAIL_TYPE_ZOOM, 1, 47 case 2:
58 frame->touches, sizeof(frame->touches)); 48 state->gid = gin_gid_begin(ge, GRAIL_TYPE_PAN, frame);
59 state->geslot = i; 49 break;
50 case 3:
51 state->gid = gin_gid_begin(ge, GRAIL_TYPE_SWIPE, frame);
52 break;
53 default:
54 return 0;
55 }
60 state->active = 1; 56 state->active = 1;
61 } 57 }
62 if (!state->zooming && fabs(dr) < move->rbar) 58 if (!move->x.active && !move->y.active)
63 return 0; 59 return 0;
64 state->zooming = 1; 60 prop[0] = move->x.active ? move->x.delta : 0;
65 prop[0] = dr; 61 prop[1] = move->y.active ? move->y.delta : 0;
66 gin_gesture_event(gin, state->geslot, 62 gru_event(ge, state->gid, move, prop, 2);
67 move->x, move->y, move->ntouch,
68 prop, 1);
69 state->r = move->r;
70 return 1; 63 return 1;
71} 64}
65
diff --git a/src/gestures-scroll.c b/src/gestures-pinch.c
index 96e153b..48e72bd 100644
--- a/src/gestures-scroll.c
+++ b/src/gestures-pinch.c
@@ -24,51 +24,40 @@
24 24
25#include "grail-recognizer.h" 25#include "grail-recognizer.h"
26#include <math.h> 26#include <math.h>
27#include <stdio.h>
27 28
28void gru_reset_scroll(struct grail *ge, 29int gru_pinch(struct grail *ge,
29 const struct touch_frame *frame) 30 const struct touch_frame *frame)
30{ 31{
31 struct gesture_inserter *gin = ge->gin;
32 struct gesture_recognizer *gru = ge->gru; 32 struct gesture_recognizer *gru = ge->gru;
33 struct scroll_model *state = &gru->scroll; 33 struct combo_model *state = &gru->pinch;
34 struct move_model *move = &gru->move;
35 gin_gesture_discard_type(gin, GRAIL_TYPE_SCROLL);
36 state->x = move->x;
37 state->y = move->y;
38 state->active = 0;
39 state->moving = 0;
40}
41
42int gru_scroll(struct grail *ge,
43 const struct touch_frame *frame)
44{
45 struct gesture_inserter *gin = ge->gin;
46 struct gesture_recognizer *gru = ge->gru;
47 struct scroll_model *state = &gru->scroll;
48 struct move_model *move = &gru->move; 34 struct move_model *move = &gru->move;
49 grail_prop_t prop[DIM_GRAIL_PROP]; 35 grail_prop_t prop[DIM_GRAIL_PROP];
50 float dx, dy; 36 if (!move->motion) {
51 int i; 37 if (state->active) {
52 dx = move->x - state->x; 38 gru_end(ge, state->gid, move);
53 dy = move->y - state->y; 39 state->active = 0;
54 if (fabs(dx) < 1 && fabs(dy) < 1) 40 }
41 return 0;
42 }
43 if (!move->r.tickle)
55 return 0; 44 return 0;
56 if (!state->active) { 45 if (!state->active) {
57 i = gin_gesture_begin(ge, GRAIL_TYPE_SCROLL, 1, 46 switch(move->ntouch) {
58 frame->touches, sizeof(frame->touches)); 47 case 2:
59 state->geslot = i; 48 state->gid = gin_gid_begin(ge, GRAIL_TYPE_PINCH, frame);
49 break;
50 case 3:
51 state->gid = gin_gid_begin(ge, GRAIL_TYPE_SCALE, frame);
52 break;
53 default:
54 return 0;
55 }
60 state->active = 1; 56 state->active = 1;
61 } 57 }
62 if (!state->moving && fabs(dx) < move->xbar && fabs(dy) < move->ybar) 58 if (!move->r.active)
63 return 0; 59 return 0;
64 state->moving = 1; 60 prop[0] = move->r.delta;
65 prop[0] = dx; 61 gru_event(ge, state->gid, move, prop, 1);
66 prop[1] = dy;
67 gin_gesture_event(gin, state->geslot,
68 move->x, move->y, move->ntouch,
69 prop, 2);
70 state->x = move->x;
71 state->y = move->y;
72 return 1; 62 return 1;
73} 63}
74
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 @@
26#include <math.h> 26#include <math.h>
27#include <stdio.h> 27#include <stdio.h>
28 28
29void gru_reset_rotate(struct grail *ge,
30 const struct touch_frame *frame)
31{
32 struct gesture_inserter *gin = ge->gin;
33 struct gesture_recognizer *gru = ge->gru;
34 struct rotate_model *state = &gru->rotate;
35 struct move_model *move = &gru->move;
36 gin_gesture_discard_type(gin, GRAIL_TYPE_ROTATE);
37 state->a = move->a;
38 state->active = 0;
39 state->rotating = 0;
40}
41
42int gru_rotate(struct grail *ge, 29int gru_rotate(struct grail *ge,
43 const struct touch_frame *frame) 30 const struct touch_frame *frame)
44{ 31{
45 struct gesture_inserter *gin = ge->gin;
46 struct gesture_recognizer *gru = ge->gru; 32 struct gesture_recognizer *gru = ge->gru;
47 struct rotate_model *state = &gru->rotate; 33 struct combo_model *state = &gru->rotate;
48 struct move_model *move = &gru->move; 34 struct move_model *move = &gru->move;
49 grail_prop_t prop[DIM_GRAIL_PROP]; 35 grail_prop_t prop[DIM_GRAIL_PROP];
50 float da; 36 if (!move->motion) {
51 int i; 37 if (state->active) {
52 da = move->a - state->a; 38 gru_end(ge, state->gid, move);
53 if (fabs(da) < 1) 39 state->active = 0;
40 }
41 return 0;
42 }
43 if (!move->a.tickle)
54 return 0; 44 return 0;
55 if (!state->active) { 45 if (!state->active) {
56 i = gin_gesture_begin(ge, 46 switch(move->ntouch) {
57 GRAIL_TYPE_ROTATE, 1, 47 case 2:
58 frame->touches, sizeof(frame->touches)); 48 state->gid = gin_gid_begin(ge, GRAIL_TYPE_ROTATE, frame);
59 state->geslot = i; 49 break;
50 case 3:
51 state->gid = gin_gid_begin(ge, GRAIL_TYPE_TURN, frame);
52 break;
53 default:
54 return 0;
55 }
60 state->active = 1; 56 state->active = 1;
61 } 57 }
62 if (!state->rotating && fabs(da) < move->abar) 58 if (!move->a.active)
63 return 0; 59 return 0;
64 state->rotating = 1; 60 prop[0] = move->a.delta;
65 prop[0] = da; 61 gru_event(ge, state->gid, move, prop, 1);
66 gin_gesture_event(gin, state->geslot,
67 move->x, move->y, move->ntouch,
68 prop, 1);
69 state->a = move->a;
70 return 1; 62 return 1;
71} 63}
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 @@
1/*****************************************************************************
2 *
3 * grail - Gesture Recognition And Instantiation Library
4 *
5 * Copyright (C) 2010 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * Authors:
21 * Henrik Rydberg <rydberg@bitmath.org>
22 *
23 ****************************************************************************/
24
25#include "grail-recognizer.h"
26#include <math.h>
27
28static const int TAP_INIT = 0;
29static const int TAP_BEGIN = 1;
30static const int TAP_END = 2;
31static const int TAP_CANCEL = 3;
32
33static const int TAP_MIN_GAP_MS = 25;
34static const int TAP_MAX_GAP_MS = 400;
35
36int gru_tapping(struct grail *ge,
37 const struct touch_frame *frame)
38{
39 struct gesture_recognizer *gru = ge->gru;
40 struct tapping_model *state = &gru->tapping;
41 struct move_model *move = &gru->move;
42 grail_prop_t prop[DIM_GRAIL_PROP];
43 if (state->status == TAP_CANCEL) {
44 if (move->ntouch)
45 return 0;
46 else
47 state->status = TAP_INIT;
48 }
49 if (move->ntouch > state->ntouch) {
50 if (!state->ntouch) {
51 state->start = frame->time;
52 state->status = TAP_BEGIN;
53 }
54 state->ntouch = move->ntouch;
55 } else if (move->ntouch < state->ntouch) {
56 if (!move->ntouch)
57 state->status = TAP_END;
58 }
59 if (state->status == TAP_INIT)
60 return 0;
61 if (state->ntouch < 1 || state->ntouch > 5) {
62 state->status = TAP_CANCEL;
63 }
64 if (frame->time - state->start > TAP_MAX_GAP_MS) {
65 state->status = TAP_CANCEL;
66 }
67 if (state->status == TAP_END &&
68 frame->time - state->start < TAP_MIN_GAP_MS) {
69 state->status = TAP_CANCEL;
70 }
71 if (state->status == TAP_CANCEL) {
72 if (state->active) {
73 gru_end(ge, state->gid, move);
74 state->active = 0;
75 }
76 state->ntouch = 0;
77 return 0;
78 }
79 if (frame->time - state->start < TAP_MIN_GAP_MS)
80 return 0;
81 if (!state->active) {
82 int type = GRAIL_TYPE_TAP1 + state->ntouch - 1;
83 state->gid = gin_gid_begin(ge, type, frame);
84 state->active = 1;
85 }
86 if (state->status != TAP_END)
87 return 0;
88 prop[0] = frame->time - state->start;
89 gin_gid_event(ge, state->gid,
90 move->x.val, move->y.val, state->ntouch,
91 prop, 1, GRAIL_STATUS_END);
92 state->status = TAP_INIT;
93 state->ntouch = 0;
94 state->active = 0;
95 return 1;
96}
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 @@
25#include "grail-recognizer.h" 25#include "grail-recognizer.h"
26#include <math.h> 26#include <math.h>
27 27
28static const float SN_MOVE = 50; 28static const float SN_MOVE = 200;
29static const float SN_ZOOM = 50; 29static const float SN_ZOOM = 200;
30static const float SN_ROTATE = 200; 30static const float SN_ROTATE = 200;
31static const float BAR_MOVE = 1; 31static const float BAR_MOVE = 4;
32static const float BAR_ZOOM = 2; 32static const float BAR_ZOOM = 12;
33static const float BAR_ROTATE = 4; 33static const float BAR_ROTATE = 12;
34 34
35static void compute_position(float *x, float *y, 35static void compute_position(float *x, float *y,
36 const struct touch_frame *frame) 36 const struct touch_frame *frame)
@@ -89,15 +89,34 @@ static float compute_rotation(float x, float y, float r,
89 return da; 89 return da;
90} 90}
91 91
92static float move_filter(float x, float x0, float fuzz) 92static float move_filter(const struct filter_model *m, float val)
93{ 93{
94 if (x > x0 - fuzz / 2 && x < x0 + fuzz / 2) 94 if (val > m->val - m->fuzz / 2 && val < m->val + m->fuzz / 2)
95 return x0; 95 return m->val;
96 if (x > x0 - fuzz && x < x0 + fuzz) 96 if (val > m->val - m->fuzz && val < m->val + m->fuzz)
97 return (x0 * 3 + x) / 4; 97 return (m->val * 3 + val) / 4;
98 if (x > x0 - fuzz * 2 && x < x0 + fuzz * 2) 98 if (val > m->val - m->fuzz * 2 && val < m->val + m->fuzz * 2)
99 return (x0 + x) / 2; 99 return (m->val + val) / 2;
100 return x; 100 return val;
101}
102
103static int move_reset(struct filter_model *m, float val)
104{
105 m->delta = 0;
106 m->tickle = 0;
107 m->active = 0;
108 m->val = val;
109 m->orig = val;
110}
111
112static int move_update(struct filter_model *m, float val)
113{
114 m->delta = val - m->val;
115 m->tickle = fabs(m->delta) > 0;
116 m->val = val;
117 if (!m->active && fabs(val - m->orig) > m->bar)
118 m->active = 1;
119 return m->active;
101} 120}
102 121
103void gru_init_motion(struct grail *ge, const struct touch_dev_caps *caps) 122void 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)
107 float x = caps->info[TP_POS_X].maximum - caps->info[TP_POS_X].minimum; 126 float x = caps->info[TP_POS_X].maximum - caps->info[TP_POS_X].minimum;
108 float y = caps->info[TP_POS_Y].maximum - caps->info[TP_POS_Y].minimum; 127 float y = caps->info[TP_POS_Y].maximum - caps->info[TP_POS_Y].minimum;
109 float r = sqrt(x * x + y * y); 128 float r = sqrt(x * x + y * y);
110 state->xfuzz = x / SN_MOVE; 129 state->x.fuzz = x / SN_MOVE;
111 state->yfuzz = y / SN_MOVE; 130 state->y.fuzz = y / SN_MOVE;
112 state->rfuzz = r / SN_ZOOM; 131 state->r.fuzz = r / SN_ZOOM;
113 state->afuzz = r / SN_ROTATE; 132 state->a.fuzz = r / SN_ROTATE;
114 state->xbar = BAR_MOVE * state->xfuzz; 133 state->x.bar = BAR_MOVE * state->x.fuzz;
115 state->ybar = BAR_MOVE * state->yfuzz; 134 state->y.bar = BAR_MOVE * state->y.fuzz;
116 state->rbar = BAR_ZOOM * state->rfuzz; 135 state->r.bar = BAR_ZOOM * state->r.fuzz;
117 state->abar = BAR_ROTATE * state->afuzz; 136 state->a.bar = BAR_ROTATE * state->a.fuzz;
137 state->motion = 0;
118} 138}
119 139
120void gru_reset_motion(struct grail *ge, 140void gru_motion(struct grail *ge,
121 const struct touch_frame *frame) 141 const struct touch_frame *frame)
122{ 142{
123 struct gesture_recognizer *gru = ge->gru; 143 struct gesture_recognizer *gru = ge->gru;
124 struct move_model *state = &gru->move; 144 struct move_model *state = &gru->move;
125 compute_position(&state->x, &state->y, frame); 145 int na = 0, nt = frame->nactive;
126 state->r = compute_radius(state->x, state->y, frame); 146 float x, y, r, a;
127 state->a = 0; 147 compute_position(&x, &y, frame);
128 state->ntouch = frame->nactive; 148 if (nt < 2 || frame->ncreate || frame->ndestroy) {
149 r = compute_radius(x, y, frame);
150 a = 0;
151 move_reset(&state->x, x);
152 move_reset(&state->y, y);
153 move_reset(&state->r, r);
154 move_reset(&state->a, a);
155 state->motion = 0;
156 } else {
157 x = move_filter(&state->x, x);
158 y = move_filter(&state->y, y);
159 r = compute_radius(x, y, frame);
160 r = move_filter(&state->r, r);
161 a = state->a.val + compute_rotation(x, y, r, &gru->frame, frame);
162 //a = move_filter(&state->a, a);
163 na += move_update(&state->x, x);
164 na += move_update(&state->y, y);
165 na += move_update(&state->r, r);
166 na += move_update(&state->a, a);
167 state->motion = 1;
168 }
169 state->nactive = na;
170 state->ntouch = nt;
171 state->time = frame->time;
129} 172}
130 173
131void gru_compute_motion(struct grail *ge, 174void gru_event(struct grail *ge, int gid,
132 const struct touch_frame *frame) 175 const struct move_model *move,
176 const grail_prop_t *prop, int nprop)
133{ 177{
134 struct gesture_inserter *gin = ge->gin; 178 gin_gid_event(ge, gid,
135 struct gesture_recognizer *gru = ge->gru; 179 move->x.val, move->y.val, move->ntouch,
136 struct move_model *state = &gru->move; 180 prop, nprop,
137 float x, y, r, a; 181 GRAIL_STATUS_UPDATE);
138 compute_position(&x, &y, frame);
139 x = move_filter(x, state->x, state->xfuzz);
140 y = move_filter(y, state->y, state->yfuzz);
141 r = compute_radius(x, y, frame);
142 r = move_filter(r, state->r, state->rfuzz);
143 a = state->a + compute_rotation(x, y, r, &gru->frame, frame);
144 a = move_filter(a, state->a, state->afuzz);
145 state->x = x;
146 state->y = y;
147 state->r = r;
148 state->a = a;
149 state->ntouch = frame->nactive;
150} 182}
183
184void gru_end(struct grail *ge, int gid, const struct move_model *move)
185{
186 gin_gid_end(ge, gid, move->x.val, move->y.val, move->ntouch);
187}
188
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 @@
27 27
28#include "grail-inserter.h" 28#include "grail-inserter.h"
29 29
30struct filter_model {
31 float delta, val, orig, fuzz, bar;
32 int tickle, active;
33};
34
30struct move_model { 35struct move_model {
31 float xfuzz, yfuzz, rfuzz, afuzz; 36 struct filter_model x, y, r, a;
32 float xbar, ybar, rbar, abar; 37 int motion, nactive, ntouch;
33 float x, y, r, a; 38 float dx, dy, dr, da;
34 int ntouch; 39 grail_time_t time;
35}; 40};
36 41
37void gru_init_motion(struct grail *ge, 42void gru_init_motion(struct grail *ge,
38 const struct touch_dev_caps *caps); 43 const struct touch_dev_caps *caps);
39void gru_reset_motion(struct grail *ge, 44void gru_motion(struct grail *ge,
40 const struct touch_frame *frame); 45 const struct touch_frame *frame);
41void gru_compute_motion(struct grail *ge, 46void gru_event(struct grail *ge, int gid,
42 const struct touch_frame *frame); 47 const struct move_model *move,
43 48 const grail_prop_t *prop, int nprop);
44struct scroll_model {
45 float x, y;
46 int active, moving, geslot;
47};
48
49void gru_reset_scroll(struct grail *ge,
50 const struct touch_frame *frame);
51int gru_scroll(struct grail *ge,
52 const struct touch_frame *frame);
53
54struct zoom_model {
55 float r;
56 int active, zooming, geslot;
57};
58 49
59void gru_reset_zoom(struct grail *ge, 50struct combo_model {
60 const struct touch_frame *frame); 51 int active, gid;
61int gru_zoom(struct grail *ge,
62 const struct touch_frame *frame);
63
64struct rotate_model {
65 float a;
66 int active, rotating, geslot;
67}; 52};
68 53
69void gru_reset_rotate(struct grail *ge, 54int gru_pan(struct grail *ge,
70 const struct touch_frame *frame); 55 const struct touch_frame *frame);
56int gru_pinch(struct grail *ge,
57 const struct touch_frame *frame);
71int gru_rotate(struct grail *ge, 58int gru_rotate(struct grail *ge,
72 const struct touch_frame *frame); 59 const struct touch_frame *frame);
60int gru_combo(struct grail *ge,
61 const struct touch_frame *frame);
73 62
74struct combo_model { 63struct tapping_model {
75 float x, y, r, a; 64 grail_time_t start;
76 int active, running, geslot; 65 int status, ntouch;
66 int active, gid;
77}; 67};
78 68
79void gru_reset_combo(struct grail *ge, 69int gru_tapping(struct grail *ge,
80 const struct touch_frame *frame); 70 const struct touch_frame *frame);
81int gru_combo(struct grail *ge,
82 const struct touch_frame *frame);
83 71
84#endif 72#endif
85 73
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 @@
29 29
30static const int MAX_GESTURE_ID = 0xfff; 30static const int MAX_GESTURE_ID = 0xfff;
31 31
32struct gesture_inserter {
33 struct slot_state state[DIM_INSTANCE];
34 grail_mask_t unused[DIM_INSTANCE_BYTES];
35 grail_mask_t fresh[DIM_INSTANCE_BYTES];
36 grail_mask_t used[DIM_INSTANCE_BYTES];
37 grail_time_t time;
38 int gestureid;
39};
40
41static int find_gslot(const struct gesture_inserter *gin, int gid)
42{
43 int i;
44 grail_mask_foreach(i, gin->used, sizeof(gin->used))
45 if (gin->state[i].id == gid)
46 return i;
47 return -1;
48}
49
32static void send_event(struct grail *ge, struct slot_state *s, 50static void send_event(struct grail *ge, struct slot_state *s,
33 const struct gesture_event *ev) 51 const struct gesture_event *ev)
34{ 52{
@@ -151,7 +169,7 @@ void gin_frame_end(struct grail *ge,
151 grail_mask_foreach(i, gin->used, sizeof(gin->used)) { 169 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
152 struct slot_state *s = &gin->state[i]; 170 struct slot_state *s = &gin->state[i];
153 if (!s->nclient || s->priority < discard) 171 if (!s->nclient || s->priority < discard)
154 gin_gesture_discard(gin, i); 172 gin_gid_discard(ge, s->id);
155 } 173 }
156 174
157 grail_mask_foreach(i, gin->used, sizeof(gin->used)) { 175 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
@@ -169,22 +187,22 @@ void gin_frame_end(struct grail *ge,
169 grail_mask_foreach(i, gin->used, sizeof(gin->used)) { 187 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
170 struct slot_state *s = &gin->state[i]; 188 struct slot_state *s = &gin->state[i];
171 if (s->status == GRAIL_STATUS_END) 189 if (s->status == GRAIL_STATUS_END)
172 gin_gesture_discard(gin, i); 190 gin_gid_discard(ge, s->id);
173 } 191 }
174 192
175 if (grail_mask_count(span, sizeof(span))) 193 if (grail_mask_count(span, sizeof(span)))
176 grail_mask_set(filtered, EV_ABS); 194 grail_mask_set(filtered, EV_ABS);
177} 195}
178 196
179int gin_gesture_begin(struct grail *ge, int type, int priority, 197int gin_gid_begin_select(struct grail *ge, int type, int priority,
180 const grail_mask_t *span, int nspan) 198 const grail_mask_t *span, int nspan)
181{ 199{
182 struct gesture_inserter *gin = ge->gin; 200 struct gesture_inserter *gin = ge->gin;
183 struct slot_state *s; 201 struct slot_state *s;
184 int geslot = grail_mask_get_first(gin->unused, sizeof(gin->unused)); 202 int i = grail_mask_get_first(gin->unused, sizeof(gin->unused));
185 if (geslot < 0) 203 if (i < 0)
186 return -1; 204 return -1;
187 s = &gin->state[geslot]; 205 s = &gin->state[i];
188 s->type = type; 206 s->type = type;
189 s->priority = priority; 207 s->priority = priority;
190 s->id = gin->gestureid++ & MAX_GESTURE_ID; 208 s->id = gin->gestureid++ & MAX_GESTURE_ID;
@@ -192,47 +210,72 @@ int gin_gesture_begin(struct grail *ge, int type, int priority,
192 s->nclient = 0; 210 s->nclient = 0;
193 memcpy(s->span, span, nspan); 211 memcpy(s->span, span, nspan);
194 gebuf_clear(&s->buf); 212 gebuf_clear(&s->buf);
195 grail_mask_clear(gin->unused, geslot); 213 grail_mask_clear(gin->unused, i);
196 grail_mask_set(gin->fresh, geslot); 214 grail_mask_set(gin->fresh, i);
197 grail_mask_set(gin->used, geslot); 215 grail_mask_set(gin->used, i);
198 return geslot; 216 return s->id;
199}
200
201void gin_gesture_end(struct gesture_inserter *gin, int geslot)
202{
203 gin->state[geslot].status = GRAIL_STATUS_END;
204} 217}
205 218
206void gin_gesture_discard(struct gesture_inserter *gin, int geslot) 219int gin_gid_begin(struct grail *ge, int type, const struct touch_frame *frame)
207{ 220{
208 gebuf_clear(&gin->state[geslot].buf); 221 return gin_gid_begin_select(ge, type, 1,
209 gin_gesture_end(gin, geslot); 222 frame->touches, sizeof(frame->touches));
210 grail_mask_clear(gin->used, geslot);
211 grail_mask_set(gin->unused, geslot);
212} 223}
213 224
214void gin_gesture_discard_type(struct gesture_inserter *gin, int type) 225void gin_gid_discard(struct grail *ge, int gid)
215{ 226{
216 int i; 227 struct gesture_inserter *gin = ge->gin;
217 grail_mask_foreach(i, gin->used, sizeof(gin->used)) 228 struct slot_state *s;
218 if (gin->state[i].type == type) 229 int i = find_gslot(gin, gid);
219 gin_gesture_discard(gin, i); 230 if (i < 0)
231 return;
232 s = &gin->state[i];
233 gebuf_clear(&s->buf);
234 s->status = GRAIL_STATUS_END;
235 grail_mask_clear(gin->used, i);
236 grail_mask_set(gin->unused, i);
220} 237}
221 238
222void gin_gesture_event(struct gesture_inserter *gin, int geslot, 239void gin_gid_event(struct grail *ge, int gid,
223 float x, float y, int ntouch, 240 float x, float y, int ntouch,
224 const grail_prop_t *prop, int nprop) 241 const grail_prop_t *prop, int nprop,
242 int status)
225{ 243{
226 struct slot_state *s = &gin->state[geslot]; 244 struct gesture_inserter *gin = ge->gin;
227 struct gesture_event ev; 245 struct gesture_event ev;
246 struct slot_state *s;
247 int i = find_gslot(gin, gid);
248 if (i < 0)
249 return;
250 s = &gin->state[i];
228 ev.ntouch = ntouch; 251 ev.ntouch = ntouch;
229 ev.nprop = nprop; 252 ev.nprop = nprop;
230 ev.time = gin->time; 253 ev.time = gin->time;
231 ev.pos.x = x; 254 ev.pos.x = x;
232 ev.pos.y = y; 255 ev.pos.y = y;
233 memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t)); 256 memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t));
234 if (s->status == GRAIL_STATUS_BEGIN)
235 s->status = GRAIL_STATUS_UPDATE;
236 gebuf_put(&s->buf, &ev); 257 gebuf_put(&s->buf, &ev);
258 if (s->status == GRAIL_STATUS_BEGIN)
259 s->status = status;
237} 260}
238 261
262void gin_gid_end(struct grail *ge, int gid,
263 float x, float y, int ntouch)
264{
265 struct gesture_inserter *gin = ge->gin;
266 struct gesture_event ev;
267 struct slot_state *s;
268 int i = find_gslot(gin, gid);
269 if (i < 0)
270 return;
271 s = &gin->state[i];
272 if (s->status != GRAIL_STATUS_BEGIN) {
273 ev.ntouch = ntouch;
274 ev.nprop = 0;
275 ev.time = gin->time;
276 ev.pos.x = x;
277 ev.pos.y = y;
278 gebuf_put(&s->buf, &ev);
279 }
280 s->status = GRAIL_STATUS_END;
281}
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 {
48 struct gebuf buf; 48 struct gebuf buf;
49}; 49};
50 50
51struct gesture_inserter {
52 struct slot_state state[DIM_INSTANCE];
53 grail_mask_t unused[DIM_INSTANCE_BYTES];
54 grail_mask_t fresh[DIM_INSTANCE_BYTES];
55 grail_mask_t used[DIM_INSTANCE_BYTES];
56 grail_time_t time;
57 int gestureid;
58};
59
60int gin_init(struct grail *ge); 51int gin_init(struct grail *ge);
61void gin_destroy(struct grail *ge); 52void gin_destroy(struct grail *ge);
62 53
@@ -64,14 +55,16 @@ void gin_frame_begin(struct grail *ge, const struct touch_frame *frame);
64void gin_frame_end(struct grail *ge, grail_mask_t *filtered, int max_filtered, 55void gin_frame_end(struct grail *ge, grail_mask_t *filtered, int max_filtered,
65 const struct touch_frame *frame); 56 const struct touch_frame *frame);
66 57
67int gin_gesture_begin(struct grail *ge, int type, int priority, 58int gin_gid_begin_select(struct grail *ge, int type, int priority,
68 const grail_mask_t *span, int nspan); 59 const grail_mask_t *span, int nspan);
69void gin_gesture_end(struct gesture_inserter *gin, int geslot); 60int gin_gid_begin(struct grail *ge, int type, const struct touch_frame *frame);
70void gin_gesture_discard(struct gesture_inserter *gin, int geslot); 61void gin_gid_discard(struct grail *ge, int gid);
71void gin_gesture_discard_type(struct gesture_inserter *gin, int type);
72 62
73void gin_gesture_event(struct gesture_inserter *gin, int geslot, 63void gin_gid_event(struct grail *ge, int gid,
74 float x, float y, int ntouch, 64 float x, float y, int ntouch,
75 const grail_prop_t *prop, int nprop); 65 const grail_prop_t *prop, int nprop,
66 int status);
67void gin_gid_end(struct grail *ge, int gid,
68 float x, float y, int ntouch);
76 69
77#endif 70#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 @@
27#include <malloc.h> 27#include <malloc.h>
28#include <errno.h> 28#include <errno.h>
29 29
30static const touch_time_t DROP_TIMEOUT_MS = 100;
31
32int gru_init(struct grail *ge, const struct touch_dev_caps *caps) 30int gru_init(struct grail *ge, const struct touch_dev_caps *caps)
33{ 31{
34 struct gesture_recognizer *gru; 32 struct gesture_recognizer *gru;
@@ -46,32 +44,15 @@ void gru_destroy(struct grail *ge)
46 ge->gru = NULL; 44 ge->gru = NULL;
47} 45}
48 46
49static void reset_gru_state(struct grail *ge, const struct touch_frame *frame)
50{
51 gru_reset_combo(ge, frame);
52 gru_reset_rotate(ge, frame);
53 gru_reset_zoom(ge, frame);
54 gru_reset_scroll(ge, frame);
55 gru_reset_motion(ge, frame);
56}
57
58void gru_recognize(struct grail *ge, const struct touch_frame *frame) 47void gru_recognize(struct grail *ge, const struct touch_frame *frame)
59{ 48{
60 struct gesture_recognizer *gru = ge->gru;
61 struct move_model *move = &gru->move;
62 if (!ge->gin || !ge->gru) 49 if (!ge->gin || !ge->gru)
63 return; 50 return;
64 if (frame->nactive < move->ntouch && 51 gru_motion(ge, frame);
65 frame->time < gru->frame.time + DROP_TIMEOUT_MS) 52 gru_pan(ge, frame);
66 return; 53 gru_pinch(ge, frame);
67 if (frame->nactive < 2 || frame->ncreate || frame->ndestroy) {
68 reset_gru_state(ge, frame);
69 return;
70 }
71 gru_compute_motion(ge, frame);
72 gru_scroll(ge, frame);
73 gru_zoom(ge, frame);
74 gru_rotate(ge, frame); 54 gru_rotate(ge, frame);
75 gru_combo(ge, frame); 55 gru_combo(ge, frame);
76 gru->frame = *frame; 56 gru_tapping(ge, frame);
57 ge->gru->frame = *frame;
77} 58}
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 @@
30struct gesture_recognizer { 30struct gesture_recognizer {
31 struct touch_frame frame; 31 struct touch_frame frame;
32 struct move_model move; 32 struct move_model move;
33 struct scroll_model scroll; 33 struct combo_model pan;
34 struct zoom_model zoom; 34 struct combo_model pinch;
35 struct rotate_model rotate; 35 struct combo_model rotate;
36 struct combo_model combo; 36 struct combo_model combo;
37 struct tapping_model tapping;
37}; 38};
38 39
39int gru_init(struct grail *ge, const struct touch_dev_caps *caps); 40int gru_init(struct grail *ge, const struct touch_dev_caps *caps);
diff --git a/test/grail.c b/test/grail.c
index 795e88f..eeaa088 100644
--- a/test/grail.c
+++ b/test/grail.c
@@ -28,6 +28,8 @@
28#include <unistd.h> 28#include <unistd.h>
29#include <fcntl.h> 29#include <fcntl.h>
30 30
31static grail_mask_t flag_mask[DIM_GRAIL_TYPE_BYTES];
32
31static int tp_get_clients(struct grail *ge, 33static int tp_get_clients(struct grail *ge,
32 struct grail_client_info *clients, int max_clients, 34 struct grail_client_info *clients, int max_clients,
33 const struct grail_coord *coords, int num_coords, 35 const struct grail_coord *coords, int num_coords,
@@ -38,22 +40,24 @@ static int tp_get_clients(struct grail *ge,
38 clients[0].id.root = 1; 40 clients[0].id.root = 1;
39 clients[0].id.event = 2; 41 clients[0].id.event = 2;
40 clients[0].id.child = 3; 42 clients[0].id.child = 3;
41 clients[0].mask[0] = 0xff; 43 memcpy(clients[0].mask, flag_mask, sizeof(flag_mask));
42 return 1; 44 return 1;
43} 45}
44 46
45static void tp_event(struct grail *ge, const struct input_event *ev) 47static void tp_event(struct grail *ge, const struct input_event *ev)
46{ 48{
49 if (!grail_mask_get(flag_mask, GRAIL_TYPE_MOVE))
50 return;
47 fprintf(stderr, "event %d 0x%x %d\n", ev->type, ev->code, ev->value); 51 fprintf(stderr, "event %d 0x%x %d\n", ev->type, ev->code, ev->value);
48} 52}
49 53
50static void tp_gesture(struct grail *ge, const struct grail_event *ev) 54static void tp_gesture(struct grail *ge, const struct grail_event *ev)
51{ 55{
52 int i; 56 int i;
53 fprintf(stderr, "gesture %d %d %d %d %f %f %d:\n", 57 fprintf(stderr, "gesture %d %d %d %d - %f %f %d - %d\n",
54 ev->type, ev->id, 58 ev->type, ev->id, ev->client_id.client, ev->client_id.event,
55 ev->client_id.client, ev->client_id.event, 59 ev->pos.x, ev->pos.y, ev->ntouch,
56 ev->pos.x, ev->pos.y, ev->ntouch); 60 ev->status);
57 for (i = 0; i < ev->nprop; i++) 61 for (i = 0; i < ev->nprop; i++)
58 fprintf(stderr, "\t%d: %f\n", i, ev->prop[i]); 62 fprintf(stderr, "\t%d: %f\n", i, ev->prop[i]);
59} 63}
@@ -62,7 +66,7 @@ static void loop_device(struct grail *ge, int fd)
62{ 66{
63 while (!grail_idle(ge, fd, 5000)) { 67 while (!grail_idle(ge, fd, 5000)) {
64 grail_pull(ge, fd); 68 grail_pull(ge, fd);
65 fprintf(stderr, "launched\n"); 69 fprintf(stderr, "\r");
66 } 70 }
67} 71}
68 72
@@ -71,8 +75,8 @@ int main(int argc, char *argv[])
71 struct grail ge; 75 struct grail ge;
72 int fd; 76 int fd;
73 77
74 if (argc < 2) { 78 if (argc < 3) {
75 fprintf(stderr, "Usage: %s <device>\n", argv[0]); 79 fprintf(stderr, "Usage: %s <mask> <device>\n", argv[0]);
76 return -1; 80 return -1;
77 } 81 }
78 82
@@ -81,7 +85,13 @@ int main(int argc, char *argv[])
81 ge.event = tp_event; 85 ge.event = tp_event;
82 ge.gesture = tp_gesture; 86 ge.gesture = tp_gesture;
83 87
84 fd = open(argv[1], O_RDONLY | O_NONBLOCK); 88 unsigned mask = atoi(argv[1]);
89 flag_mask[0] = (mask >> 0) & 255;
90 flag_mask[1] = (mask >> 8) & 255;
91 flag_mask[2] = (mask >> 16) & 255;
92 flag_mask[3] = (mask >> 24) & 255;
93
94 fd = open(argv[2], O_RDONLY | O_NONBLOCK);
85 if (fd < 0) { 95 if (fd < 0) {
86 fprintf(stderr, "error: could not open device\n"); 96 fprintf(stderr, "error: could not open device\n");
87 return -1; 97 return -1;
diff --git a/test/touch.c b/test/touch.c
index 9b2d38a..8893c0d 100644
--- a/test/touch.c
+++ b/test/touch.c
@@ -39,13 +39,14 @@ static void tp_sync(struct touch_engine *engine,
39{ 39{
40 struct touch_frame *frame = &engine->frame; 40 struct touch_frame *frame = &engine->frame;
41 int i, j; 41 int i, j;
42 fprintf(stderr, "sync %d %lld\n", frame->nactive, frame->time);
43 for (i = 0; i < frame->nactive; i++) { 42 for (i = 0; i < frame->nactive; i++) {
44 struct touch *t = frame->active[i]; 43 struct touch *t = frame->active[i];
45 fprintf(stderr, "touch %d %d\n", i, t->slot); 44 fprintf(stderr, "touch %d %d\n", i, t->slot);
46 for (j = 0; j < DIM_TOUCH_PROP; j++) 45 for (j = 0; j < DIM_TOUCH_PROP; j++)
47 fprintf(stderr, " %d\n", t->prop[j]); 46 fprintf(stderr, " %d\n", t->prop[j]);
48 } 47 }
48 fprintf(stderr, "sync %d %lld %d %d\n",
49 frame->nactive, frame->time, frame->ncreate, frame->ndestroy);
49} 50}
50 51
51static void loop_device(struct touch_dev *dev, int fd) 52static void loop_device(struct touch_dev *dev, int fd)