summaryrefslogtreecommitdiff
path: root/src/touch-dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/touch-dev.c')
-rw-r--r--src/touch-dev.c179
1 files changed, 179 insertions, 0 deletions
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}