summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2010-08-06 21:11:17 +0200
committerHenrik Rydberg <rydberg@euromail.se>2010-08-06 21:11:17 +0200
commit7db9d8d76ff61c4802ac15559dcea6fa54ff567a (patch)
treeb67e040c0abeb0ab1fca72754a767dc9ab851461 /src
initial bzr repo at rev 27
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am36
-rw-r--r--src/evbuf.h64
-rw-r--r--src/gebuf.h70
-rw-r--r--src/gestures-combo.c71
-rw-r--r--src/gestures-pan.c68
-rw-r--r--src/gestures-pinch.c68
-rw-r--r--src/gestures-rotate.c66
-rw-r--r--src/gestures-tapping.c101
-rw-r--r--src/grail-api.c115
-rw-r--r--src/grail-bits.c94
-rw-r--r--src/grail-gestures.c188
-rw-r--r--src/grail-gestures.h77
-rw-r--r--src/grail-inserter.c282
-rw-r--r--src/grail-inserter.h71
-rw-r--r--src/grail-recognizer.c58
-rw-r--r--src/grail-recognizer.h44
-rw-r--r--src/touch-dev.c218
-rw-r--r--src/touch-engine.c137
18 files changed, 1828 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..7dc3ac2
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,36 @@
1lib_LTLIBRARIES = libgrail.la
2
3libgrail_la_LDFLAGS = \
4 -version-info @LIB_VERSION@ \
5 -lm \
6 $(MTDEV_LIBS)
7
8libgrail_la_SOURCES = \
9 evbuf.h \
10 gebuf.h \
11 touch-dev.c \
12 touch-engine.c \
13 grail-bits.c \
14 grail-inserter.c \
15 grail-inserter.h \
16 grail-gestures.c \
17 grail-gestures.h \
18 gestures-pan.c \
19 gestures-pinch.c \
20 gestures-rotate.c \
21 gestures-combo.c \
22 gestures-tapping.c \
23 grail-recognizer.c \
24 grail-recognizer.h \
25 grail-api.c
26
27AM_CFLAGS = $(CWARNFLAGS)
28
29INCLUDES = -I$(top_srcdir)/include/
30
31libgrailincludedir = $(includedir)
32libgrailinclude_HEADERS = \
33 $(top_srcdir)/include/grail-bits.h \
34 $(top_srcdir)/include/grail-types.h \
35 $(top_srcdir)/include/grail-touch.h \
36 $(top_srcdir)/include/grail.h
diff --git a/src/evbuf.h b/src/evbuf.h
new file mode 100644
index 0000000..dc5ad1e
--- /dev/null
+++ b/src/evbuf.h
@@ -0,0 +1,64 @@
1/*****************************************************************************
2 *
3 * mtdev - Multitouch Protocol Translation Library (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
6 * Copyright (C) 2010 Canonical Ltd.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 ****************************************************************************/
28
29#ifndef GRAIL_EVBUF_H
30#define GRAIL_EVBUF_H
31
32#define DIM_EVENTS 512
33
34struct evbuf {
35 int head;
36 int tail;
37 struct input_event buffer[DIM_EVENTS];
38};
39
40static inline void evbuf_clear(struct evbuf *evbuf)
41{
42 evbuf->head = evbuf->tail = 0;
43}
44
45static inline int evbuf_empty(const struct evbuf *evbuf)
46{
47 return evbuf->head == evbuf->tail;
48}
49
50static inline void evbuf_put(struct evbuf *evbuf,
51 const struct input_event *ev)
52{
53 evbuf->buffer[evbuf->head++] = *ev;
54 evbuf->head &= DIM_EVENTS - 1;
55}
56
57static inline void evbuf_get(struct evbuf *evbuf,
58 struct input_event *ev)
59{
60 *ev = evbuf->buffer[evbuf->tail++];
61 evbuf->tail &= DIM_EVENTS - 1;
62}
63
64#endif
diff --git a/src/gebuf.h b/src/gebuf.h
new file mode 100644
index 0000000..3f71ab5
--- /dev/null
+++ b/src/gebuf.h
@@ -0,0 +1,70 @@
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#ifndef _GRAIL_GESTURE_BUFFER_H
26#define _GRAIL_GESTURE_BUFFER_H
27
28#include <grail.h>
29
30#define DIM_GESTURE_EVENTS 512
31
32struct gesture_event {
33 int ntouch;
34 int nprop;
35 touch_time_t time;
36 struct grail_coord pos;
37 grail_prop_t prop[DIM_GRAIL_PROP];
38};
39
40struct gebuf {
41 int head;
42 int tail;
43 struct gesture_event buffer[DIM_GESTURE_EVENTS];
44};
45
46static inline void gebuf_clear(struct gebuf *gebuf)
47{
48 gebuf->head = gebuf->tail = 0;
49}
50
51static inline int gebuf_empty(const struct gebuf *gebuf)
52{
53 return gebuf->head == gebuf->tail;
54}
55
56static inline void gebuf_put(struct gebuf *gebuf,
57 const struct gesture_event *ev)
58{
59 gebuf->buffer[gebuf->head++] = *ev;
60 gebuf->head &= DIM_GESTURE_EVENTS - 1;
61}
62
63static inline void gebuf_get(struct gebuf *gebuf,
64 struct gesture_event *ev)
65{
66 *ev = gebuf->buffer[gebuf->tail++];
67 gebuf->tail &= DIM_GESTURE_EVENTS - 1;
68}
69
70#endif
diff --git a/src/gestures-combo.c b/src/gestures-combo.c
new file mode 100644
index 0000000..7b8dbd5
--- /dev/null
+++ b/src/gestures-combo.c
@@ -0,0 +1,71 @@
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#include <stdio.h>
28
29static const int getype[DIM_TOUCH + 1] = {
30 0,
31 0,
32 GRAIL_TYPE_COMBO2,
33 GRAIL_TYPE_COMBO3,
34 GRAIL_TYPE_COMBO4,
35 GRAIL_TYPE_COMBO5,
36};
37
38int gru_combo(struct grail *ge,
39 const struct touch_frame *frame)
40{
41 struct gesture_recognizer *gru = ge->gru;
42 struct combo_model *state = &gru->combo;
43 struct move_model *move = &gru->move;
44 grail_prop_t prop[DIM_GRAIL_PROP];
45 if (!move->multi) {
46 if (state->active) {
47 gru_end(ge, state->gid, move);
48 state->active = 0;
49 }
50 return 0;
51 }
52 if (!move->x.tickle && !move->y.tickle &&
53 !move->r.tickle && !move->a.tickle)
54 return 0;
55 if (!state->active) {
56 int type = getype[move->ntouch];
57 if (!type)
58 return 0;
59 state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
60 state->active = 1;
61 }
62 if (!move->x.active && !move->y.active &&
63 !move->r.active && !move->a.active)
64 return 0;
65 prop[0] = move->x.active ? move->x.delta : 0;
66 prop[1] = move->y.active ? move->y.delta : 0;
67 prop[2] = move->r.active ? move->r.delta : 0;
68 prop[3] = move->a.active ? move->a.delta : 0;
69 gru_event(ge, state->gid, move, prop, 4);
70 return 1;
71}
diff --git a/src/gestures-pan.c b/src/gestures-pan.c
new file mode 100644
index 0000000..3094007
--- /dev/null
+++ b/src/gestures-pan.c
@@ -0,0 +1,68 @@
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#include <stdio.h>
28
29static const int getype[DIM_TOUCH + 1] = {
30 0,
31 0,
32 GRAIL_TYPE_PAN,
33 GRAIL_TYPE_SWIPE,
34 GRAIL_TYPE_BRUSH,
35 GRAIL_TYPE_HAND,
36};
37
38int gru_pan(struct grail *ge,
39 const struct touch_frame *frame)
40{
41 struct gesture_recognizer *gru = ge->gru;
42 struct combo_model *state = &gru->pan;
43 struct move_model *move = &gru->move;
44 grail_prop_t prop[DIM_GRAIL_PROP];
45 if (!move->multi) {
46 if (state->active) {
47 gru_end(ge, state->gid, move);
48 state->active = 0;
49 }
50 return 0;
51 }
52 if (!move->x.tickle && !move->y.tickle)
53 return 0;
54 if (!state->active) {
55 int type = getype[move->ntouch];
56 if (!type)
57 return 0;
58 state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
59 state->active = 1;
60 }
61 if (!move->x.active && !move->y.active)
62 return 0;
63 prop[0] = move->x.active ? move->x.delta : 0;
64 prop[1] = move->y.active ? move->y.delta : 0;
65 gru_event(ge, state->gid, move, prop, 2);
66 return 1;
67}
68
diff --git a/src/gestures-pinch.c b/src/gestures-pinch.c
new file mode 100644
index 0000000..0721e02
--- /dev/null
+++ b/src/gestures-pinch.c
@@ -0,0 +1,68 @@
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#include <stdio.h>
28
29static const int getype[DIM_TOUCH + 1] = {
30 0,
31 0,
32 GRAIL_TYPE_PINCH,
33 GRAIL_TYPE_SCALE,
34 GRAIL_TYPE_PICK,
35 GRAIL_TYPE_GRAB,
36};
37
38int gru_pinch(struct grail *ge,
39 const struct touch_frame *frame)
40{
41 struct gesture_recognizer *gru = ge->gru;
42 struct combo_model *state = &gru->pinch;
43 struct move_model *move = &gru->move;
44 grail_prop_t prop[DIM_GRAIL_PROP];
45 if (!move->multi) {
46 if (state->active) {
47 gru_end(ge, state->gid, move);
48 state->active = 0;
49 }
50 return 0;
51 }
52 if (!move->a.tickle)
53 return 0;
54 if (!move->r.tickle)
55 return 0;
56 if (!state->active) {
57 int type = getype[move->ntouch];
58 if (!type)
59 return 0;
60 state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
61 state->active = 1;
62 }
63 if (!move->r.active)
64 return 0;
65 prop[0] = move->r.delta;
66 gru_event(ge, state->gid, move, prop, 1);
67 return 1;
68}
diff --git a/src/gestures-rotate.c b/src/gestures-rotate.c
new file mode 100644
index 0000000..6c496d2
--- /dev/null
+++ b/src/gestures-rotate.c
@@ -0,0 +1,66 @@
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#include <stdio.h>
28
29static const int getype[DIM_TOUCH + 1] = {
30 0,
31 0,
32 GRAIL_TYPE_ROTATE,
33 GRAIL_TYPE_TURN,
34 GRAIL_TYPE_WHIRL,
35 GRAIL_TYPE_REVOLVE,
36};
37
38int gru_rotate(struct grail *ge,
39 const struct touch_frame *frame)
40{
41 struct gesture_recognizer *gru = ge->gru;
42 struct combo_model *state = &gru->rotate;
43 struct move_model *move = &gru->move;
44 grail_prop_t prop[DIM_GRAIL_PROP];
45 if (!move->multi) {
46 if (state->active) {
47 gru_end(ge, state->gid, move);
48 state->active = 0;
49 }
50 return 0;
51 }
52 if (!move->a.tickle)
53 return 0;
54 if (!state->active) {
55 int type = getype[move->ntouch];
56 if (!type)
57 return 0;
58 state->gid = gin_gid_begin(ge, type, PRIO_GESTURE, frame);
59 state->active = 1;
60 }
61 if (!move->a.active)
62 return 0;
63 prop[0] = move->a.delta;
64 gru_event(ge, state->gid, move, prop, 1);
65 return 1;
66}
diff --git a/src/gestures-tapping.c b/src/gestures-tapping.c
new file mode 100644
index 0000000..cc0e685
--- /dev/null
+++ b/src/gestures-tapping.c
@@ -0,0 +1,101 @@
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_BEGIN = 0;
29static const int TAP_END = 1;
30static const int TAP_CANCEL = 2;
31
32static const int TAP_MIN_GAP_MS = 25;
33static const int TAP_MAX_GAP_MS = 300;
34
35int gru_tapping(struct grail *ge,
36 const struct touch_frame *frame)
37{
38 struct gesture_recognizer *gru = ge->gru;
39 struct tapping_model *state = &gru->tapping;
40 struct move_model *move = &gru->move;
41 grail_prop_t prop[DIM_GRAIL_PROP];
42 if (move->ntouch) {
43 if (state->status == TAP_CANCEL)
44 return 0;
45 state->status = TAP_BEGIN;
46 if (!state->ntouch)
47 state->start = move->time;
48 if (move->ntouch > state->ntouch) {
49 state->ntouch = move->ntouch;
50 if (state->active) {
51 gin_gid_discard(ge, state->gid);
52 state->active = 0;
53 }
54 state->x = move->x.val;
55 state->y = move->y.val;
56 } else if (state->ntouch == 1) {
57 if (fabs(move->x.val - state->x) > move->y.bar ||
58 fabs(move->y.val - state->y) > move->y.bar)
59 state->status = TAP_CANCEL;
60 }
61 if (!state->active) {
62 int type = GRAIL_TYPE_TAP1 + state->ntouch - 1;
63 state->gid = gin_gid_begin(ge, type, PRIO_TAP, frame);
64 state->active = 1;
65 }
66 } else if (state->status == TAP_BEGIN && state->ntouch) {
67 state->status = TAP_END;
68 } else {
69 state->status = TAP_BEGIN;
70 state->ntouch = 0;
71 return 0;
72 }
73 if (state->ntouch < 1 || state->ntouch > 5)
74 state->status = TAP_CANCEL;
75 if (move->time - state->start > TAP_MAX_GAP_MS)
76 state->status = TAP_CANCEL;
77 if (state->status == TAP_END &&
78 move->time - state->start < TAP_MIN_GAP_MS)
79 state->status = TAP_CANCEL;
80 if (move->x.active || move->y.active)
81 state->status = TAP_CANCEL;
82 if (state->status == TAP_CANCEL) {
83 if (state->active) {
84 gin_gid_discard(ge, state->gid);
85 state->active = 0;
86 }
87 state->ntouch = 0;
88 return 0;
89 }
90 if (state->status != TAP_END ||
91 move->time - state->start < TAP_MIN_GAP_MS)
92 return 0;
93 prop[0] = move->time - state->start;
94 gin_gid_event(ge, state->gid,
95 move->x.val, move->y.val, state->ntouch,
96 prop, 1, GRAIL_STATUS_END);
97 state->status = TAP_BEGIN;
98 state->ntouch = 0;
99 state->active = 0;
100 return 1;
101}
diff --git a/src/grail-api.c b/src/grail-api.c
new file mode 100644
index 0000000..9ceb1e7
--- /dev/null
+++ b/src/grail-api.c
@@ -0,0 +1,115 @@
1#include "grail-inserter.h"
2#include "grail-recognizer.h"
3#include <grail.h>
4#include <string.h>
5#include <stdio.h>
6#include <unistd.h>
7#include <fcntl.h>
8#include <malloc.h>
9#include <errno.h>
10#include "evbuf.h"
11
12struct grail_impl {
13 struct touch_dev dev;
14 struct touch_engine engine;
15 struct evbuf evbuf;
16};
17
18static void tp_event(struct touch_engine *engine,
19 const struct input_event *ev)
20{
21 struct grail *ge = engine->priv;
22 struct grail_impl *x = ge->impl;
23 evbuf_put(&x->evbuf, ev);
24}
25
26static void tp_sync(struct touch_engine *engine,
27 const struct input_event *syn)
28{
29 struct input_event ev;
30 struct grail *ge = engine->priv;
31 struct grail_impl *x = ge->impl;
32 struct touch_frame *frame = &engine->frame;
33 grail_mask_t filtered[DIM_EV_TYPE_BYTES];
34 int nevent = 0;
35 gin_frame_begin(ge, frame);
36 gru_recognize(ge, frame);
37 gin_frame_end(ge, filtered, sizeof(filtered), frame);
38 if (!ge->event) {
39 evbuf_clear(&x->evbuf);
40 return;
41 }
42 while (!evbuf_empty(&x->evbuf)) {
43 evbuf_get(&x->evbuf, &ev);
44 if (grail_mask_get(filtered, ev.type))
45 continue;
46 ge->event(ge, &ev);
47 nevent++;
48 }
49 if (nevent)
50 ge->event(ge, syn);
51}
52
53int grail_open(struct grail *ge, int fd)
54{
55 struct grail_impl *x;
56 int ret;
57 x = calloc(1, sizeof(*x));
58 if (!x)
59 return -ENOMEM;
60 ge->impl = x;
61 ret = gin_init(ge);
62 if (ret)
63 goto freemem;
64 ret = touch_dev_open(&x->dev, fd);
65 if (ret)
66 goto freegin;
67 ret = gru_init(ge);
68 if (ret)
69 goto freedev;
70 touch_engine_init(&x->engine, tp_event, tp_sync, ge);
71 touch_engine_attach(&x->engine, &x->dev);
72 return 0;
73 freedev:
74 touch_dev_close(&x->dev, fd);
75 freegin:
76 gin_destroy(ge);
77 freemem:
78 free(x);
79 ge->impl = 0;
80 return ret;
81}
82
83void grail_close(struct grail *ge, int fd)
84{
85 struct grail_impl *x = ge->impl;
86 void *status;
87 touch_engine_detach(&x->engine, &x->dev);
88 gru_destroy(ge);
89 touch_dev_close(&x->dev, fd);
90 gin_destroy(ge);
91 free(ge->impl);
92 ge->impl = 0;
93}
94
95int grail_idle(struct grail *ge, int fd, int ms)
96{
97 struct grail_impl *x = ge->impl;
98 return touch_dev_idle(&x->dev, fd, ms);
99}
100
101int grail_pull(struct grail *ge, int fd)
102{
103 struct grail_impl *x = ge->impl;
104 return touch_dev_pull(&x->dev, fd);
105}
106
107void grail_get_units(struct grail_coord *min, struct grail_coord *max,
108 const struct grail *ge)
109{
110 const struct touch_dev_caps *caps = &ge->impl->dev.caps;
111 min->x = caps->info[TP_POS_X].minimum;
112 min->y = caps->info[TP_POS_Y].minimum;
113 max->x = caps->info[TP_POS_X].maximum;
114 max->y = caps->info[TP_POS_Y].maximum;
115}
diff --git a/src/grail-bits.c b/src/grail-bits.c
new file mode 100644
index 0000000..1b38d58
--- /dev/null
+++ b/src/grail-bits.c
@@ -0,0 +1,94 @@
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-bits.h"
26
27static const int grail_bits_in_byte[256] =
28{
29 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
30 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
31 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
32 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
33 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
34 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
35 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
36 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
37};
38
39static const int grail_first_set_bit[256] =
40{
41 -1,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
42 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
43 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
44 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
45 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
46 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
47 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
48 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
49};
50
51void grail_mask_set_mask(grail_mask_t *a, const grail_mask_t *b, int bytes)
52{
53 while (bytes--)
54 *a++ |= *b++;
55}
56
57void grail_mask_clear_mask(grail_mask_t *a, const grail_mask_t *b, int bytes)
58{
59 while (bytes--)
60 *a++ &= ~*b++;
61}
62
63int grail_mask_count(const grail_mask_t *mask, int bytes)
64{
65 int count = 0;
66 while (bytes--)
67 count += grail_bits_in_byte[*mask++];
68 return count;
69}
70
71int grail_mask_get_first(const grail_mask_t *mask, int bytes)
72{
73 int k;
74 for (k = 0; k < bytes; k++)
75 if (mask[k])
76 return (k << 3) | grail_first_set_bit[mask[k]];
77 return -1;
78}
79
80int grail_mask_get_next(int i, const grail_mask_t *mask, int bytes)
81{
82 int k = ++i >> 3;
83 if (k < bytes) {
84 i = grail_first_set_bit[mask[k] & (~0 << (i & 7))];
85 if (i >= 0)
86 return (k << 3) | i;
87 while (++k < bytes) {
88 i = grail_first_set_bit[mask[k]];
89 if (i >= 0)
90 return (k << 3) | i;
91 }
92 }
93 return -1;
94}
diff --git a/src/grail-gestures.c b/src/grail-gestures.c
new file mode 100644
index 0000000..e1bf622
--- /dev/null
+++ b/src/grail-gestures.c
@@ -0,0 +1,188 @@
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 float SN_MOVE = 200;
29static const float SN_ZOOM = 200;
30static const float SN_ROTATE = 200;
31static const float BAR_MOVE = 4;
32static const float BAR_ZOOM = 12;
33static const float BAR_ROTATE = 12;
34
35static void compute_position(float *x, float *y,
36 const struct touch_frame *frame)
37{
38 int i, n = frame->nactive;
39 *x = 0;
40 *y = 0;
41 if (n < 1)
42 return;
43 for (i = 0; i < n; i++) {
44 const struct touch *t = frame->active[i];
45 *x += t->prop[TP_POS_X];
46 *y += t->prop[TP_POS_Y];
47 }
48 *x /= n;
49 *y /= n;
50}
51
52static float compute_radius(float x, float y,
53 const struct touch_frame *frame)
54{
55 int i, n = frame->nactive;
56 float r = 0, r2 = 0;
57 if (n < 2)
58 return r;
59 for (i = 0; i < n; i++) {
60 const struct touch *t = frame->active[i];
61 float dx = t->prop[TP_POS_X] - x;
62 float dy = t->prop[TP_POS_Y] - y;
63 r2 += dx * dx + dy * dy;
64 }
65 r2 /= n;
66 r = sqrt(r2);
67 return r;
68}
69
70static float compute_rotation(float x, float y, float r,
71 const struct touch_frame *prev,
72 const struct touch_frame *frame)
73{
74 int i, n = frame->nactive;
75 float da = 0, da2 = 0;
76 if (n < 2)
77 return da;
78 for (i = 0; i < n; i++) {
79 const struct touch *t = frame->active[i];
80 const struct touch *ot = &prev->touch[t->slot];
81 float dx = t->prop[TP_POS_X] - x;
82 float dy = t->prop[TP_POS_Y] - y;
83 float mx = t->prop[TP_POS_X] - ot->prop[TP_POS_X];
84 float my = t->prop[TP_POS_Y] - ot->prop[TP_POS_Y];
85 da2 += dx * my - dy * mx;
86 }
87 da2 /= n;
88 da = da2 / r;
89 return da;
90}
91
92static float move_filter(const struct filter_model *m, float val)
93{
94 if (val > m->val - m->fuzz / 2 && val < m->val + m->fuzz / 2)
95 return m->val;
96 if (val > m->val - m->fuzz && val < m->val + m->fuzz)
97 return (m->val * 3 + val) / 4;
98 if (val > m->val - m->fuzz * 2 && val < m->val + m->fuzz * 2)
99 return (m->val + val) / 2;
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;
120}
121
122void gru_init_motion(struct grail *ge)
123{
124 struct gesture_recognizer *gru = ge->gru;
125 struct move_model *state = &gru->move;
126 struct grail_coord min, max;
127 grail_get_units(&min, &max, ge);
128 float x = max.x - min.x;
129 float y = max.y - min.y;
130 float r = sqrt(x * x + y * y);
131 state->x.fuzz = x / SN_MOVE;
132 state->y.fuzz = y / SN_MOVE;
133 state->r.fuzz = r / SN_ZOOM;
134 state->a.fuzz = r / SN_ROTATE;
135 state->x.bar = BAR_MOVE * state->x.fuzz;
136 state->y.bar = BAR_MOVE * state->y.fuzz;
137 state->r.bar = BAR_ZOOM * state->r.fuzz;
138 state->a.bar = BAR_ROTATE * state->a.fuzz;
139 state->multi = 0;
140}
141
142void gru_motion(struct grail *ge,
143 const struct touch_frame *frame)
144{
145 struct gesture_recognizer *gru = ge->gru;
146 struct move_model *state = &gru->move;
147 float x, y, r, a;
148 compute_position(&x, &y, frame);
149 if (frame->nactive < 2 || frame->ncreate || frame->ndestroy) {
150 r = compute_radius(x, y, frame);
151 a = 0;
152 move_reset(&state->x, x);
153 move_reset(&state->y, y);
154 move_reset(&state->r, r);
155 move_reset(&state->a, a);
156 state->multi = 0;
157 } else {
158 x = move_filter(&state->x, x);
159 y = move_filter(&state->y, y);
160 r = compute_radius(x, y, frame);
161 r = move_filter(&state->r, r);
162 a = state->a.val + compute_rotation(x, y, r, &gru->frame, frame);
163 //a = move_filter(&state->a, a);
164 move_update(&state->x, x);
165 move_update(&state->y, y);
166 move_update(&state->r, r);
167 move_update(&state->a, a);
168 state->multi = 1;
169 }
170 state->ntouch = frame->nactive;
171 state->time = frame->time;
172}
173
174void gru_event(struct grail *ge, int gid,
175 const struct move_model *move,
176 const grail_prop_t *prop, int nprop)
177{
178 gin_gid_event(ge, gid,
179 move->x.val, move->y.val, move->ntouch,
180 prop, nprop,
181 GRAIL_STATUS_UPDATE);
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
new file mode 100644
index 0000000..663d357
--- /dev/null
+++ b/src/grail-gestures.h
@@ -0,0 +1,77 @@
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#ifndef _GRAIL_GESTURES_H
26#define _GRAIL_GESTURES_H
27
28#include "grail-inserter.h"
29
30#define PRIO_POINTER 1
31#define PRIO_GESTURE 2
32#define PRIO_TAP 3
33
34struct filter_model {
35 float delta, val, orig, fuzz, bar;
36 int tickle, active;
37};
38
39struct move_model {
40 struct filter_model x, y, r, a;
41 int multi, ntouch;
42 float dx, dy, dr, da;
43 grail_time_t time;
44};
45
46void gru_init_motion(struct grail *ge);
47void gru_motion(struct grail *ge,
48 const struct touch_frame *frame);
49void gru_event(struct grail *ge, int gid,
50 const struct move_model *move,
51 const grail_prop_t *prop, int nprop);
52
53struct combo_model {
54 int active, gid;
55};
56
57int gru_pan(struct grail *ge,
58 const struct touch_frame *frame);
59int gru_pinch(struct grail *ge,
60 const struct touch_frame *frame);
61int gru_rotate(struct grail *ge,
62 const struct touch_frame *frame);
63int gru_combo(struct grail *ge,
64 const struct touch_frame *frame);
65
66struct tapping_model {
67 grail_time_t start;
68 float x, y;
69 int status, ntouch;
70 int active, gid;
71};
72
73int gru_tapping(struct grail *ge,
74 const struct touch_frame *frame);
75
76#endif
77
diff --git a/src/grail-inserter.c b/src/grail-inserter.c
new file mode 100644
index 0000000..724052c
--- /dev/null
+++ b/src/grail-inserter.c
@@ -0,0 +1,282 @@
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-inserter.h"
26#include <malloc.h>
27#include <string.h>
28#include <errno.h>
29
30static const int MAX_GESTURE_ID = 0xfff;
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
50static void send_event(struct grail *ge, struct slot_state *s,
51 const struct gesture_event *ev)
52{
53 struct grail_event gev;
54 int i;
55 if (!ge->gesture)
56 return;
57 gev.type = s->type;
58 gev.id = s->id;
59 gev.status = s->status;
60 gev.ntouch = ev->ntouch;
61 gev.nprop = ev->nprop;
62 gev.time = ev->time;
63 gev.pos = ev->pos;
64 memcpy(gev.prop, ev->prop, ev->nprop * sizeof(grail_prop_t));
65 for (i = 0; i < s->nclient; i++) {
66 gev.client_id = s->client_id[i];
67 ge->gesture(ge, &gev);
68 }
69}
70
71// todo: spanning tree for multi-user case
72static void setup_new_gestures(struct grail *ge,
73 const struct touch_frame *frame)
74{
75 struct gesture_inserter *gin = ge->gin;
76 grail_mask_t types[DIM_GRAIL_TYPE_BYTES];
77 grail_mask_t span[DIM_TOUCH_BYTES];
78 struct grail_client_info info[DIM_CLIENT];
79 int i, j, nclient = 0;
80 int nfresh = grail_mask_count(gin->fresh, sizeof(gin->fresh));
81 if (!nfresh)
82 return;
83
84 memset(types, 0, sizeof(types));
85 memset(span, 0, sizeof(span));
86
87 grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) {
88 struct slot_state *s = &gin->state[i];
89 grail_mask_set(types, s->type);
90 grail_mask_set_mask(span, s->span, sizeof(span));
91 }
92
93 if (ge->get_clients) {
94 struct grail_coord coord[DIM_CLIENT];
95 int ncoord = 0;
96 grail_mask_foreach(i, span, sizeof(span)) {
97 const struct touch *t = &frame->touch[i];
98 coord[ncoord].x = t->prop[TP_POS_X];
99 coord[ncoord].y = t->prop[TP_POS_Y];
100 ncoord++;
101 }
102 nclient = ge->get_clients(ge, info, DIM_CLIENT,
103 coord, ncoord, types, sizeof(types));
104 }
105
106 grail_mask_foreach(i, gin->fresh, sizeof(gin->fresh)) {
107 struct slot_state *s = &gin->state[i];
108 s->nclient = 0;
109 for (j = 0; j < nclient; j++) {
110 if (!grail_mask_get(info[j].mask, s->type))
111 continue;
112 s->client_id[s->nclient++] = info[j].id;
113 }
114 }
115
116 memset(gin->fresh, 0, sizeof(gin->fresh));
117}
118
119int gin_init(struct grail *ge)
120{
121 struct gesture_inserter *gin;
122 int i;
123 gin = calloc(1, sizeof(*gin));
124 if (!gin)
125 return -ENOMEM;
126 for (i = 0; i < DIM_INSTANCE; i++)
127 grail_mask_set(gin->unused, i);
128 ge->gin = gin;
129 return 0;
130}
131
132void gin_destroy(struct grail *ge)
133{
134 free(ge->gin);
135 ge->gin = NULL;
136}
137
138void gin_frame_begin(struct grail *ge, const struct touch_frame *frame)
139{
140 struct gesture_inserter *gin = ge->gin;
141 gin->time = frame->time;
142}
143
144void gin_frame_end(struct grail *ge,
145 grail_mask_t *filtered, int max_filtered,
146 const struct touch_frame *frame)
147{
148 struct gesture_inserter *gin = ge->gin;
149 grail_mask_t span[DIM_INSTANCE_BYTES];
150 int i, hold = 0, discard = 0;
151
152 memset(filtered, 0, max_filtered);
153 memset(span, 0, sizeof(span));
154
155 setup_new_gestures(ge, frame);
156
157 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
158 struct slot_state *s = &gin->state[i];
159 if (!s->nclient)
160 continue;
161 if (s->priority > hold)
162 hold = s->priority;
163 if (s->status == GRAIL_STATUS_BEGIN)
164 continue;
165 if (s->priority > discard)
166 discard = s->priority;
167 }
168
169 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
170 struct slot_state *s = &gin->state[i];
171 if (!s->nclient || s->priority < discard)
172 gin_gid_discard(ge, s->id);
173 }
174
175 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
176 struct slot_state *s = &gin->state[i];
177 struct gesture_event ev;
178 grail_mask_set_mask(span, s->span, sizeof(span));
179 if (s->priority < hold)
180 continue;
181 while (!gebuf_empty(&s->buf)) {
182 gebuf_get(&s->buf, &ev);
183 send_event(ge, s, &ev);
184 }
185 }
186
187 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
188 struct slot_state *s = &gin->state[i];
189 if (s->status == GRAIL_STATUS_END)
190 gin_gid_discard(ge, s->id);
191 }
192
193 if (grail_mask_count(span, sizeof(span)))
194 grail_mask_set(filtered, EV_ABS);
195}
196
197int gin_gid_begin_select(struct grail *ge, int type, int priority,
198 const grail_mask_t *span, int nspan)
199{
200 struct gesture_inserter *gin = ge->gin;
201 struct slot_state *s;
202 int i = grail_mask_get_first(gin->unused, sizeof(gin->unused));
203 if (i < 0)
204 return -1;
205 s = &gin->state[i];
206 s->type = type;
207 s->priority = priority;
208 s->id = gin->gestureid++ & MAX_GESTURE_ID;
209 s->status = GRAIL_STATUS_BEGIN;
210 s->nclient = 0;
211 memcpy(s->span, span, nspan);
212 gebuf_clear(&s->buf);
213 grail_mask_clear(gin->unused, i);
214 grail_mask_set(gin->fresh, i);
215 grail_mask_set(gin->used, i);
216 return s->id;
217}
218
219int gin_gid_begin(struct grail *ge, int type, int priority,
220 const struct touch_frame *frame)
221{
222 return gin_gid_begin_select(ge, type, priority,
223 frame->touches, sizeof(frame->touches));
224}
225
226void gin_gid_discard(struct grail *ge, int gid)
227{
228 struct gesture_inserter *gin = ge->gin;
229 struct slot_state *s;
230 int i = find_gslot(gin, gid);
231 if (i < 0)
232 return;
233 s = &gin->state[i];
234 gebuf_clear(&s->buf);
235 s->status = GRAIL_STATUS_END;
236 grail_mask_clear(gin->used, i);
237 grail_mask_set(gin->unused, i);
238}
239
240void gin_gid_event(struct grail *ge, int gid,
241 float x, float y, int ntouch,
242 const grail_prop_t *prop, int nprop,
243 int status)
244{
245 struct gesture_inserter *gin = ge->gin;
246 struct gesture_event ev;
247 struct slot_state *s;
248 int i = find_gslot(gin, gid);
249 if (i < 0)
250 return;
251 s = &gin->state[i];
252 ev.ntouch = ntouch;
253 ev.nprop = nprop;
254 ev.time = gin->time;
255 ev.pos.x = x;
256 ev.pos.y = y;
257 memcpy(ev.prop, prop, nprop * sizeof(grail_prop_t));
258 gebuf_put(&s->buf, &ev);
259 if (s->status == GRAIL_STATUS_BEGIN)
260 s->status = status;
261}
262
263void gin_gid_end(struct grail *ge, int gid,
264 float x, float y, int ntouch)
265{
266 struct gesture_inserter *gin = ge->gin;
267 struct gesture_event ev;
268 struct slot_state *s;
269 int i = find_gslot(gin, gid);
270 if (i < 0)
271 return;
272 s = &gin->state[i];
273 if (s->status != GRAIL_STATUS_BEGIN) {
274 ev.ntouch = ntouch;
275 ev.nprop = 0;
276 ev.time = gin->time;
277 ev.pos.x = x;
278 ev.pos.y = y;
279 gebuf_put(&s->buf, &ev);
280 }
281 s->status = GRAIL_STATUS_END;
282}
diff --git a/src/grail-inserter.h b/src/grail-inserter.h
new file mode 100644
index 0000000..3ffacec
--- /dev/null
+++ b/src/grail-inserter.h
@@ -0,0 +1,71 @@
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#ifndef _GRAIL_INSERTER_H
26#define _GRAIL_INSERTER_H
27
28#include <grail-touch.h>
29#include <grail.h>
30#include "gebuf.h"
31
32#define DIM_EV_TYPE EV_CNT
33#define DIM_EV_TYPE_BYTES ((DIM_EV_TYPE + 7) >> 3)
34
35#define DIM_INSTANCE 32
36#define DIM_INSTANCE_BYTES ((DIM_INSTANCE + 7) >> 3)
37
38#define DIM_CLIENT 32
39
40struct slot_state {
41 int type;
42 int priority;
43 int id;
44 int status;
45 int nclient;
46 struct grail_client_id client_id[DIM_CLIENT];
47 grail_mask_t span[DIM_TOUCH_BYTES];
48 struct gebuf buf;
49};
50
51int gin_init(struct grail *ge);
52void gin_destroy(struct grail *ge);
53
54void gin_frame_begin(struct grail *ge, const struct touch_frame *frame);
55void gin_frame_end(struct grail *ge, grail_mask_t *filtered, int max_filtered,
56 const struct touch_frame *frame);
57
58int gin_gid_begin_select(struct grail *ge, int type, int priority,
59 const grail_mask_t *span, int nspan);
60int gin_gid_begin(struct grail *ge, int type, int priority,
61 const struct touch_frame *frame);
62void gin_gid_discard(struct grail *ge, int gid);
63
64void gin_gid_event(struct grail *ge, int gid,
65 float x, float y, int ntouch,
66 const grail_prop_t *prop, int nprop,
67 int status);
68void gin_gid_end(struct grail *ge, int gid,
69 float x, float y, int ntouch);
70
71#endif
diff --git a/src/grail-recognizer.c b/src/grail-recognizer.c
new file mode 100644
index 0000000..587a12a
--- /dev/null
+++ b/src/grail-recognizer.c
@@ -0,0 +1,58 @@
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 <string.h>
27#include <malloc.h>
28#include <errno.h>
29
30int gru_init(struct grail *ge)
31{
32 struct gesture_recognizer *gru;
33 gru = calloc(1, sizeof(struct gesture_recognizer));
34 if (!gru)
35 return -ENOMEM;
36 ge->gru = gru;
37 gru_init_motion(ge);
38 return 0;
39}
40
41void gru_destroy(struct grail *ge)
42{
43 free(ge->gru);
44 ge->gru = NULL;
45}
46
47void gru_recognize(struct grail *ge, const struct touch_frame *frame)
48{
49 if (!ge->gin || !ge->gru)
50 return;
51 gru_motion(ge, frame);
52 gru_pan(ge, frame);
53 gru_pinch(ge, frame);
54 gru_rotate(ge, frame);
55 gru_combo(ge, frame);
56 gru_tapping(ge, frame);
57 ge->gru->frame = *frame;
58}
diff --git a/src/grail-recognizer.h b/src/grail-recognizer.h
new file mode 100644
index 0000000..8a5ac80
--- /dev/null
+++ b/src/grail-recognizer.h
@@ -0,0 +1,44 @@
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#ifndef _GRAIL_RECOGNIZER_H
26#define _GRAIL_RECOGNIZER_H
27
28#include "grail-gestures.h"
29
30struct gesture_recognizer {
31 struct touch_frame frame;
32 struct move_model move;
33 struct combo_model pan;
34 struct combo_model pinch;
35 struct combo_model rotate;
36 struct combo_model combo;
37 struct tapping_model tapping;
38};
39
40int gru_init(struct grail *ge);
41void gru_recognize(struct grail *ge, const struct touch_frame *frame);
42void gru_destroy(struct grail *ge);
43
44#endif
diff --git a/src/touch-dev.c b/src/touch-dev.c
new file mode 100644
index 0000000..4cc8d55
--- /dev/null
+++ b/src/touch-dev.c
@@ -0,0 +1,218 @@
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-touch.h>
26#include <malloc.h>
27#include <string.h>
28#include <errno.h>
29
30/* from mtdev-mapping.h */
31#define MT_TOUCH_MAJOR 0
32#define MT_TOUCH_MINOR 1
33#define MT_WIDTH_MAJOR 2
34#define MT_WIDTH_MINOR 3
35#define MT_ORIENTATION 4
36#define MT_POSITION_X 5
37#define MT_POSITION_Y 6
38#define MT_TRACKING_ID 9
39#define MT_PRESSURE 10
40
41int mtdev_fetch_event(struct mtdev *dev, int fd, struct input_event *ev);
42void mtdev_put_event(struct mtdev *dev, const struct input_event *ev);
43int mtdev_empty(struct mtdev *dev);
44void mtdev_get_event(struct mtdev *dev, struct input_event* ev);
45
46struct touch_dev_impl {
47 int id[DIM_TOUCH];
48 int slot;
49 int status;
50 grail_mask_t mask[DIM_TOUCH_BYTES];
51 touch_prop_t prop[DIM_TOUCH_PROP];
52 struct mtdev mtdev;
53};
54
55static inline void set_info(struct touch_dev_caps *caps, int code,
56 const struct input_absinfo *info)
57{
58 grail_mask_set(caps->mask, code);
59 caps->info[code] = *info;
60}
61
62static void set_caps(struct touch_dev_caps *caps,
63 const struct mtdev_caps *mtcaps)
64{
65 if (mtcaps->has_abs[MT_POSITION_X])
66 set_info(caps, TP_POS_X, &mtcaps->abs[MT_POSITION_X]);
67 if (mtcaps->has_abs[MT_POSITION_Y])
68 set_info(caps, TP_POS_Y, &mtcaps->abs[MT_POSITION_Y]);
69 if (mtcaps->has_abs[MT_TOUCH_MAJOR])
70 set_info(caps, TP_TOUCH_MAJOR, &mtcaps->abs[MT_TOUCH_MAJOR]);
71 if (mtcaps->has_abs[MT_TOUCH_MINOR])
72 set_info(caps, TP_TOUCH_MINOR, &mtcaps->abs[MT_TOUCH_MINOR]);
73 if (mtcaps->has_abs[MT_WIDTH_MAJOR])
74 set_info(caps, TP_WIDTH_MAJOR, &mtcaps->abs[MT_WIDTH_MAJOR]);
75 if (mtcaps->has_abs[MT_WIDTH_MINOR])
76 set_info(caps, TP_WIDTH_MINOR, &mtcaps->abs[MT_WIDTH_MINOR]);
77 if (mtcaps->has_abs[MT_ORIENTATION])
78 set_info(caps, TP_ORIENTATION, &mtcaps->abs[MT_ORIENTATION]);
79 if (mtcaps->has_abs[MT_PRESSURE])
80 set_info(caps, TP_PRESSURE, &mtcaps->abs[MT_PRESSURE]);
81}
82
83static inline void set_prop(struct touch_dev_impl *x, int code, int value)
84{
85 grail_mask_set(x->mask, code);
86 x->prop[code] = value;
87}
88
89static void finish_touch(struct touch_dev *dev,
90 struct touch_dev_impl *x)
91{
92 if (x->status < 0 && dev->destroy)
93 dev->destroy(dev, x->slot);
94 if (x->status > 0 && dev->create)
95 dev->create(dev, x->slot, x->mask, x->prop);
96 if (x->status == 0 && dev->modify &&
97 grail_mask_count(x->mask, sizeof(x->mask)))
98 dev->modify(dev, x->slot, x->mask, x->prop);
99 x->status = 0;
100 memset(x->mask, 0, sizeof(x->mask));
101}
102
103static void finish_packet(struct touch_dev *dev,
104 const struct input_event *syn)
105{
106 finish_touch(dev, dev->impl);
107 if (dev->sync)
108 dev->sync(dev, syn);
109}
110
111static int handle_abs_event(struct touch_dev *dev,
112 const struct input_event *ev)
113{
114 struct touch_dev_impl *x = dev->impl;
115 switch (ev->code) {
116 case ABS_MT_SLOT:
117 if (ev->value >= 0 && ev->value < DIM_TOUCH) {
118 if (x->slot != ev->value)
119 finish_touch(dev, x);
120 x->slot = ev->value;
121 }
122 return 1;
123 case ABS_MT_POSITION_X:
124 set_prop(x, TP_POS_X, ev->value);
125 return 1;
126 case ABS_MT_POSITION_Y:
127 set_prop(x, TP_POS_Y, ev->value);
128 return 1;
129 case ABS_MT_TOUCH_MAJOR:
130 set_prop(x, TP_TOUCH_MAJOR, ev->value);
131 return 1;
132 case ABS_MT_TOUCH_MINOR:
133 set_prop(x, TP_TOUCH_MINOR, ev->value);
134 return 1;
135 case ABS_MT_WIDTH_MAJOR:
136 set_prop(x, TP_WIDTH_MAJOR, ev->value);
137 return 1;
138 case ABS_MT_WIDTH_MINOR:
139 set_prop(x, TP_WIDTH_MINOR, ev->value);
140 return 1;
141 case ABS_MT_ORIENTATION:
142 set_prop(x, TP_ORIENTATION, ev->value);
143 return 1;
144 case ABS_MT_PRESSURE:
145 set_prop(x, TP_PRESSURE, ev->value);
146 return 1;
147 case ABS_MT_TRACKING_ID:
148 if (x->id[x->slot] != ev->value) {
149 if (x->id[x->slot] != MT_ID_NULL) {
150 x->status = -1;
151 finish_touch(dev, x);
152 }
153 if (ev->value != MT_ID_NULL)
154 x->status = 1;
155 }
156 x->id[x->slot] = ev->value;
157 return 1;
158 default:
159 return 0;
160 }
161}
162
163int touch_dev_open(struct touch_dev *dev, int fd)
164{
165 struct touch_dev_impl *x;
166 int ret, i;
167 memset(dev, 0, sizeof(*dev));
168 x = calloc(1, sizeof(*x));
169 if (!x)
170 return -ENOMEM;
171 ret = mtdev_open(&x->mtdev, fd);
172 if (!ret && !x->mtdev.caps.has_mtdata)
173 ret = -ENODEV;
174 if (ret)
175 goto error;
176 for (i = 0; i < DIM_TOUCH; i++)
177 x->id[i] = MT_ID_NULL;
178 set_caps(&dev->caps, &x->mtdev.caps);
179 dev->impl = x;
180 return 0;
181 error:
182 free(x);
183 return ret;
184}
185
186int touch_dev_idle(struct touch_dev *dev, int fd, int ms)
187{
188 return mtdev_idle(&dev->impl->mtdev, fd, ms);
189}
190
191int touch_dev_pull(struct touch_dev *dev, int fd)
192{
193 struct touch_dev_impl *x = dev->impl;
194 struct input_event ev;
195 int ret, count = 0, consumed;
196 while ((ret = mtdev_get(&x->mtdev, fd, &ev, 1)) > 0) {
197 consumed = 0;
198 if (ev.type == EV_SYN) {
199 if (ev.code == SYN_REPORT)
200 finish_packet(dev, &ev);
201 consumed++;
202 } else if (ev.type == EV_ABS) {
203 consumed += handle_abs_event(dev, &ev);
204 }
205 if (!consumed && dev->event)
206 dev->event(dev, &ev);
207 count++;
208 }
209 return count > 0 ? count : ret;
210}
211
212void touch_dev_close(struct touch_dev *dev, int fd)
213{
214 struct touch_dev_impl *x = dev->impl;
215 mtdev_close(&x->mtdev);
216 free(x);
217 memset(dev, 0, sizeof(*dev));
218}
diff --git a/src/touch-engine.c b/src/touch-engine.c
new file mode 100644
index 0000000..3e6870e
--- /dev/null
+++ b/src/touch-engine.c
@@ -0,0 +1,137 @@
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-touch.h>
26#include <string.h>
27
28static void tp_event(struct touch_dev *dev, const struct input_event *ev)
29{
30 struct touch_engine *engine = dev->priv;
31 if (engine && engine->event)
32 engine->event(engine, ev);
33}
34
35static void update_frame(struct touch_frame *frame,
36 int slot, int active,
37 const grail_mask_t *mask,
38 const touch_prop_t *prop)
39{
40 struct touch *t = &frame->touch[slot];
41 int i;
42 t->active = active;
43 grail_mask_modify(frame->touches, slot, active);
44 if (mask && prop)
45 grail_mask_foreach(i, mask, DIM_TOUCH_PROP_BYTES)
46 t->prop[i] = prop[i];
47}
48
49static void finalize_frame(struct touch_frame *frame, touch_time_t time)
50{
51 int i, nslot = 0;
52 grail_mask_foreach(i, frame->touches, DIM_TOUCH_BYTES)
53 frame->active[nslot++] = &frame->touch[i];
54 frame->nactive = nslot;
55 frame->time = time;
56}
57
58static void tp_create(struct touch_dev *dev, int slot,
59 const grail_mask_t *mask, const touch_prop_t *prop)
60{
61 struct touch_engine *engine = dev->priv;
62 if (engine) {
63 engine->frame.ncreate++;
64 update_frame(&engine->frame, slot, 1, mask, prop);
65 }
66}
67
68static void tp_modify(struct touch_dev *dev, int slot,
69 const grail_mask_t *mask, const touch_prop_t *prop)
70{
71 struct touch_engine *engine = dev->priv;
72 if (engine) {
73 engine->frame.nmodify++;
74 update_frame(&engine->frame, slot, 1, mask, prop);
75 }
76}
77
78static void tp_destroy(struct touch_dev *dev, int slot)
79{
80 struct touch_engine *engine = dev->priv;
81 if (engine) {
82 engine->frame.ndestroy++;
83 update_frame(&engine->frame, slot, 0, 0, 0);
84 }
85}
86
87static void tp_sync(struct touch_dev *dev, const struct input_event *syn)
88{
89 static const touch_time_t ms = 1000;
90 struct touch_engine *engine = dev->priv;
91 touch_time_t time = syn->time.tv_usec / ms + syn->time.tv_sec * ms;
92 if (engine) {
93 finalize_frame(&engine->frame, time);
94 if (engine->sync)
95 engine->sync(engine, syn);
96 engine->frame.ncreate = 0;
97 engine->frame.nmodify = 0;
98 engine->frame.ndestroy = 0;
99 }
100}
101
102void touch_engine_init(struct touch_engine *engine,
103 void (*event)(struct touch_engine *engine,
104 const struct input_event *ev),
105 void (*sync)(struct touch_engine *engine,
106 const struct input_event *ev),
107 void *priv)
108{
109 int i;
110 memset(engine, 0, sizeof(*engine));
111 for (i = 0; i < DIM_TOUCH; i++)
112 engine->frame.touch[i].slot = i;
113 engine->event = event;
114 engine->sync = sync;
115 engine->priv = priv;
116}
117
118void touch_engine_attach(struct touch_engine *engine, struct touch_dev *dev)
119{
120 dev->priv = engine;
121 dev->event = tp_event;
122 dev->create = tp_create;
123 dev->modify = tp_modify;
124 dev->destroy = tp_destroy;
125 dev->sync = tp_sync;
126}
127
128void touch_engine_detach(struct touch_engine *engine, struct touch_dev *dev)
129{
130 dev->sync = 0;
131 dev->destroy = 0;
132 dev->modify = 0;
133 dev->create = 0;
134 dev->event = 0;
135 dev->priv = 0;
136}
137