summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am16
-rw-r--r--src/gesture-client.c113
-rw-r--r--src/gesture-dev.c106
-rw-r--r--src/touch-dev.c179
-rw-r--r--src/touch-engine.c126
5 files changed, 540 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..69ff759
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,16 @@
1lib_LTLIBRARIES = libgrail.la
2
3libgrail_la_LDFLAGS = -version-info @LIB_VERSION@
4
5libgrail_la_SOURCES = \
6 touch-dev.c \
7 touch-engine.c \
8 gesture-client.c \
9 gesture-dev.c
10
11AM_CFLAGS = $(CWARNFLAGS)
12
13INCLUDES = -I$(top_srcdir)/include/
14
15libgrailincludedir = $(includedir)
16libgrailinclude_HEADERS = $(top_srcdir)/include/grail.h
diff --git a/src/gesture-client.c b/src/gesture-client.c
new file mode 100644
index 0000000..3b8eb5d
--- /dev/null
+++ b/src/gesture-client.c
@@ -0,0 +1,113 @@
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 <gesture-client.h>
26#include <gesture-buffer.h>
27#include <malloc.h>
28#include <string.h>
29#include <errno.h>
30
31#define GESTURE_GAP (1000 * 60 * 60)
32
33struct client_impl {
34 enum gesture_state state;
35 touch_time_t begin, end;
36 struct gebuf buf;
37};
38
39int client_init(struct gesture_client *client, void *priv)
40{
41 struct client_impl *x;
42 memset(client, 0, sizeof(*client));
43 x = calloc(DIM_GESTURE_TYPE, sizeof(*x));
44 if (!x)
45 return -ENOMEM;
46 client->impl = x;
47 client->priv = priv;
48 return 0;
49}
50
51void client_flag(struct gesture_client *client,
52 const struct gesture_flag *flag)
53{
54 if (client->priority[flag->type]) {
55 struct client_impl *x = &client->impl[flag->type];
56 switch(flag->state) {
57 case GS_BEGIN:
58 x->begin = flag->time;
59 x->end = flag->time + GESTURE_GAP;
60 break;
61 case GS_CANCEL:
62 x->end = x->begin;
63 break;
64 case GS_END:
65 x->end = flag->time;
66 break;
67 }
68 x->state = flag->state;
69 }
70}
71
72void client_event(struct gesture_client *client,
73 const struct gesture_event *ev)
74{
75 if (client->priority[ev->type]) {
76 struct client_impl *x = &client->impl[ev->type];
77 gebuf_put(&x->buf, ev);
78 }
79}
80
81void client_sync(struct gesture_client *client)
82{
83 struct gesture_event ev;
84 struct client_impl *x = client->impl;
85 int i, prio = 0;
86 for (i = 0; i < DIM_GESTURE_TYPE; i++) {
87 if (x[i].begin != x[i].end) {
88 if (client->priority[i] > prio)
89 prio = client->priority[i];
90 }
91 }
92 for (i = 0; i < DIM_GESTURE_TYPE; i++) {
93 if (client->priority[i] < prio) {
94 gebuf_clear(&x[i].buf);
95 } else if (prio && client->gesture) {
96 if (x[i].state == GS_END) {
97 while (!gebuf_empty(&x[i].buf)) {
98 gebuf_get(&x[i].buf, &ev);
99 client->gesture(client, &ev);
100 }
101 }
102 }
103 }
104 for (i = 0; i < DIM_GESTURE_TYPE; i++)
105 if (x[i].state == GS_END)
106 x[i].begin = x[i].end;
107}
108
109void client_destroy(struct gesture_client *client)
110{
111 free(client->impl);
112 memset(client, 0, sizeof(*client));
113}
diff --git a/src/gesture-dev.c b/src/gesture-dev.c
new file mode 100644
index 0000000..b49b8ea
--- /dev/null
+++ b/src/gesture-dev.c
@@ -0,0 +1,106 @@
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 <gesture-dev.h>
26#include <gesture-buffer.h>
27#include <malloc.h>
28#include <string.h>
29#include <errno.h>
30
31#define DIM_CLIENT 32
32
33struct gedev_impl {
34 int nclient;
35 struct gesture_client *client[DIM_CLIENT];
36};
37
38int gedev_init(struct gesture_dev *dev, void *priv)
39{
40 struct gedev_impl *x;
41 x = calloc(1, sizeof(*x));
42 if (!x)
43 return -ENOMEM;
44 dev->impl = x;
45 dev->priv = priv;
46 return 0;
47}
48
49int gedev_attach_client(struct gesture_dev *dev,
50 struct gesture_client *client)
51{
52 struct gedev_impl *x = dev->impl;
53 if (x->nclient >= DIM_CLIENT)
54 return -ENOMEM;
55 x->client[x->nclient++] = client;
56 return 0;
57}
58
59void gedev_flag(struct gesture_dev *dev,
60 const struct gesture_flag *flag)
61{
62 struct gedev_impl *x = dev->impl;
63 int i;
64 for (i = 0; i < x->nclient; i++)
65 client_flag(x->client[i], flag);
66}
67
68void gedev_event(struct gesture_dev *dev,
69 const struct gesture_event *ev)
70{
71 struct gedev_impl *x = dev->impl;
72 int i;
73 for (i = 0; i < x->nclient; i++)
74 client_event(x->client[i], ev);
75}
76
77void gedev_sync(struct gesture_dev *dev)
78{
79 struct gedev_impl *x = dev->impl;
80 int i;
81 for (i = 0; i < x->nclient; i++)
82 client_sync(x->client[i]);
83}
84
85void gedev_detach_client(struct gesture_dev *dev,
86 struct gesture_client *client)
87{
88 struct gedev_impl *x = dev->impl;
89 int i, j;
90 for (i = 0; i < x->nclient; i++)
91 if (x->client[i] == client)
92 break;
93 if (i >= x->nclient)
94 return;
95 x->nclient--;
96 for (j = i; j < x->nclient; j++)
97 x->client[j] = x->client[j + 1];
98 for (j = x->nclient; j < DIM_CLIENT; j++)
99 x->client[j] = 0;
100}
101
102void gedev_destroy(struct gesture_dev *dev)
103{
104 free(dev->impl);
105 memset(dev, 0, sizeof(*dev));
106}
diff --git a/src/touch-dev.c b/src/touch-dev.c
new file mode 100644
index 0000000..9e140ca
--- /dev/null
+++ b/src/touch-dev.c
@@ -0,0 +1,179 @@
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 <touch-dev.h>
26#include <malloc.h>
27#include <string.h>
28#include <errno.h>
29
30#define DIM_TOUCH 32
31
32struct touch_dev_impl {
33 int id[DIM_TOUCH];
34 int slot;
35 int status;
36 touch_prop_mask_t mask[1];
37 touch_prop_t prop[DIM_TOUCH_PROP];
38 struct mtdev mtdev;
39};
40
41static inline int has_any_prop(const touch_prop_mask_t *mask)
42{
43 return mask[0] != 0;
44}
45
46static inline void set_prop(struct touch_dev_impl *x, int code, int value)
47{
48 x->mask[code >> 5] |= 1U << (code & 31);
49 x->prop[code] = value;
50}
51
52static void finish_touch(struct touch_dev *dev,
53 struct touch_dev_impl *x)
54{
55 if (x->status < 0 && dev->destroy)
56 dev->destroy(dev, x->slot);
57 if (x->status > 0 && dev->create)
58 dev->create(dev, x->slot, x->mask, x->prop);
59 if (x->status == 0 && has_any_prop(x->mask) && dev->modify)
60 dev->modify(dev, x->slot, x->mask, x->prop);
61 x->status = 0;
62 memset(x->mask, 0, sizeof(x->mask));
63}
64
65static void finish_packet(struct touch_dev *dev,
66 const struct input_event *syn)
67{
68 static const touch_time_t ms = 1000;
69 touch_time_t time = syn->time.tv_usec / ms + syn->time.tv_sec * ms;
70 finish_touch(dev, dev->impl);
71 if (dev->sync)
72 dev->sync(dev, time);
73}
74
75static int handle_abs_event(struct touch_dev *dev,
76 const struct input_event *ev)
77{
78 struct touch_dev_impl *x = dev->impl;
79 switch (ev->code) {
80 case ABS_MT_SLOT:
81 if (ev->value >= 0 && ev->value < DIM_TOUCH) {
82 if (x->slot != ev->value)
83 finish_touch(dev, x);
84 x->slot = ev->value;
85 }
86 return 1;
87 case ABS_MT_POSITION_X:
88 set_prop(x, TP_POS_X, ev->value);
89 return 1;
90 case ABS_MT_POSITION_Y:
91 set_prop(x, TP_POS_Y, ev->value);
92 return 1;
93 case ABS_MT_TOUCH_MAJOR:
94 set_prop(x, TP_TOUCH_MAJOR, ev->value);
95 return 1;
96 case ABS_MT_TOUCH_MINOR:
97 set_prop(x, TP_TOUCH_MINOR, ev->value);
98 return 1;
99 case ABS_MT_WIDTH_MAJOR:
100 set_prop(x, TP_WIDTH_MAJOR, ev->value);
101 return 1;
102 case ABS_MT_WIDTH_MINOR:
103 set_prop(x, TP_WIDTH_MINOR, ev->value);
104 return 1;
105 case ABS_MT_ORIENTATION:
106 set_prop(x, TP_ORIENTATION, ev->value);
107 return 1;
108 case ABS_MT_PRESSURE:
109 set_prop(x, TP_PRESSURE, ev->value);
110 return 1;
111 case ABS_MT_TRACKING_ID:
112 if (x->id[x->slot] != ev->value) {
113 if (x->id[x->slot] != MT_ID_NULL) {
114 x->status = -1;
115 finish_touch(dev, x);
116 }
117 if (ev->value != MT_ID_NULL)
118 x->status = 1;
119 }
120 x->id[x->slot] = ev->value;
121 return 1;
122 default:
123 return 0;
124 }
125}
126
127int touch_dev_open(struct touch_dev *dev, int fd)
128{
129 struct touch_dev_impl *x;
130 int ret, i;
131 memset(dev, 0, sizeof(*dev));
132 x = calloc(1, sizeof(*x));
133 if (!x)
134 return -ENOMEM;
135 ret = mtdev_open(&x->mtdev, fd);
136 if (ret)
137 goto error;
138 for (i = 0; i < DIM_TOUCH; i++)
139 x->id[i] = MT_ID_NULL;
140 dev->impl = x;
141 return 0;
142 error:
143 free(x);
144 return ret;
145}
146
147int touch_dev_idle(struct touch_dev *dev, int fd, int ms)
148{
149 return mtdev_idle(&dev->impl->mtdev, fd, ms);
150}
151
152int touch_dev_pull(struct touch_dev *dev, int fd)
153{
154 struct touch_dev_impl *x = dev->impl;
155 struct input_event ev;
156 int ret, count = 0, consumed;
157 while ((ret = mtdev_get(&x->mtdev, fd, &ev, 1)) > 0) {
158 consumed = 0;
159 if (ev.type == EV_SYN) {
160 if (ev.code == SYN_REPORT)
161 finish_packet(dev, &ev);
162 consumed++;
163 } else if (ev.type == EV_ABS) {
164 consumed += handle_abs_event(dev, &ev);
165 }
166 if (!consumed && dev->event)
167 dev->event(dev, &ev);
168 count++;
169 }
170 return count > 0 ? count : ret;
171}
172
173void touch_dev_close(struct touch_dev *dev, int fd)
174{
175 struct touch_dev_impl *x = dev->impl;
176 mtdev_close(&x->mtdev);
177 free(x);
178 memset(dev, 0, sizeof(*dev));
179}
diff --git a/src/touch-engine.c b/src/touch-engine.c
new file mode 100644
index 0000000..b6774f3
--- /dev/null
+++ b/src/touch-engine.c
@@ -0,0 +1,126 @@
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 <touch-engine.h>
26#include <string.h>
27
28static void tp_event(struct touch_dev *dev, const struct input_event *ev)
29{
30}
31
32static void update_frame(struct touch_frame *frame,
33 int slot, int active,
34 const touch_prop_mask_t *mask,
35 const touch_prop_t *prop)
36{
37 struct touch *touch = &frame->touch[slot];
38 touch->active = active;
39 if (mask && prop) {
40 for (int i = 0; i < DIM_TOUCH_PROP; i++)
41 if (has_prop(mask, i))
42 touch->prop[i] = prop[i];
43 }
44}
45
46static void finalize_frame(struct touch_frame *frame)
47{
48 int last = -1;
49 frame->ntouch = 0;
50 frame->slot = -1;
51 for (int i = 0; i < DIM_TOUCH_PROP; i++) {
52 frame->touch[i].next = -1;
53 if (frame->touch[i].active) {
54 if (last < 0)
55 frame->slot = i;
56 else
57 frame->touch[last].next = i;
58 last = i;
59 frame->ntouch++;
60 }
61 }
62}
63
64static void tp_create(struct touch_dev *dev, int slot,
65 const touch_prop_mask_t *mask, const touch_prop_t *prop)
66{
67 struct touch_engine *engine = dev->priv;
68 if (engine)
69 update_frame(&engine->frame, slot, 1, mask, prop);
70}
71
72static void tp_modify(struct touch_dev *dev, int slot,
73 const touch_prop_mask_t *mask, const touch_prop_t *prop)
74{
75 struct touch_engine *engine = dev->priv;
76 if (engine)
77 update_frame(&engine->frame, slot, 1, mask, prop);
78}
79
80static void tp_destroy(struct touch_dev *dev, int slot)
81{
82 struct touch_engine *engine = dev->priv;
83 if (engine)
84 update_frame(&engine->frame, slot, 0, 0, 0);
85}
86
87static void tp_sync(struct touch_dev *dev, touch_time_t time)
88{
89 struct touch_engine *engine = dev->priv;
90 if (engine) {
91 finalize_frame(&engine->frame);
92 if (engine->sync)
93 engine->sync(engine, time);
94 }
95}
96
97void touch_engine_init(struct touch_engine *engine,
98 void (*sync)(struct touch_engine *engine,
99 touch_time_t time),
100 void *priv)
101{
102 memset(engine, 0, sizeof(*engine));
103 engine->sync = sync;
104 engine->priv = priv;
105}
106
107void touch_engine_attach(struct touch_engine *engine, struct touch_dev *dev)
108{
109 dev->priv = engine;
110 dev->event = tp_event;
111 dev->create = tp_create;
112 dev->modify = tp_modify;
113 dev->destroy = tp_destroy;
114 dev->sync = tp_sync;
115}
116
117void touch_engine_detach(struct touch_engine *engine, struct touch_dev *dev)
118{
119 dev->sync = 0;
120 dev->destroy = 0;
121 dev->modify = 0;
122 dev->create = 0;
123 dev->event = 0;
124 dev->priv = 0;
125}
126