debian: Add graphviz dependency
[gfxprim/pasky.git] / libs / input / GP_InputDriverLinux.c
blob93bbdef1983906060622a90fa379cb403bfdbb8d
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <linux/input.h>
30 #include "core/GP_Debug.h"
32 #include "input/GP_EventQueue.h"
33 #include "input/GP_InputDriverLinux.h"
35 static int get_version(int fd)
37 int ver;
39 if (ioctl(fd, EVIOCGVERSION, &ver))
40 return -1;
42 GP_DEBUG(2, "Input version %u.%u.%u",
43 ver>>16, (ver>>8)&0xff, ver&0xff);
45 return 0;
49 * Returns size on success just as read()
51 static int get_name(int fd, char *buf, size_t buf_len)
53 int ret;
55 if ((ret = ioctl(fd, EVIOCGNAME(buf_len), buf)) <= 0)
56 return -1;
58 return ret;
61 static void print_name(int fd)
63 char name[64];
65 if (GP_GetDebugLevel() < 2)
66 return;
68 if (get_name(fd, name, sizeof(name)) > 0)
69 GP_DEBUG(2, "Input device name '%s'", name);
72 static void try_load_callibration(struct GP_InputDriverLinux *self)
74 long bit = 0;
75 int abs[5];
77 ioctl(self->fd, EVIOCGBIT(EV_ABS, EV_ABS), &bit);
79 if (!bit) {
80 GP_DEBUG(3, "Not an absolute input device");
81 return;
84 if (!ioctl(self->fd, EVIOCGABS(ABS_X), abs)) {
85 GP_DEBUG(3, "ABS X = <%i,%i> Fuzz %i Flat %i",
86 abs[1], abs[2], abs[3], abs[4]);
87 self->abs_x_max = abs[2];
90 if (!ioctl(self->fd, EVIOCGABS(ABS_Y), abs)) {
91 GP_DEBUG(3, "ABS Y = <%i,%i> Fuzz %i Flat %i",
92 abs[1], abs[2], abs[3], abs[4]);
93 self->abs_y_max = abs[2];
96 if (!ioctl(self->fd, EVIOCGABS(ABS_PRESSURE), abs)) {
97 GP_DEBUG(3, "ABS P = <%i,%i> Fuzz %i Flat %i",
98 abs[1], abs[2], abs[3], abs[4]);
99 self->abs_press_max = abs[2];
103 struct GP_InputDriverLinux *GP_InputDriverLinuxOpen(const char *path)
105 int fd;
106 struct GP_InputDriverLinux *ret;
108 GP_DEBUG(2, "Opening '%s'", path);
110 fd = open(path, O_RDONLY | O_NONBLOCK);
112 if (fd < 0) {
113 GP_DEBUG(1, "Failed to open '%s': %s", path, strerror(errno));
114 return NULL;
117 if (get_version(fd)) {
118 GP_DEBUG(1, "Failed ioctl(), not a input device?");
119 return NULL;
122 print_name(fd);
124 ret = malloc(sizeof(struct GP_InputDriverLinux));
126 if (ret == NULL) {
127 GP_DEBUG(1, "Malloc failed :(");
128 close(fd);
129 return NULL;
132 ret->fd = fd;
134 ret->rel_x = 0;
135 ret->rel_y = 0;
136 ret->rel_flag = 0;
138 ret->abs_x = 0;
139 ret->abs_y = 0;
140 ret->abs_press = 0;
141 ret->abs_flag_x = 0;
142 ret->abs_flag_y = 0;
143 ret->abs_pen_flag = 1;
145 try_load_callibration(ret);
147 return ret;
150 void GP_InputDriverLinuxClose(struct GP_InputDriverLinux *self)
152 GP_DEBUG(1, "Closing input device");
153 print_name(self->fd);
155 close(self->fd);
156 free(self);
159 static void input_rel(struct GP_InputDriverLinux *self, struct input_event *ev)
161 GP_DEBUG(4, "Relative event");
163 switch (ev->code) {
164 case REL_X:
165 self->rel_x = ev->value;
166 self->rel_flag = 1;
167 break;
168 case REL_Y:
169 self->rel_y = ev->value;
170 self->rel_flag = 1;
171 break;
172 default:
173 GP_DEBUG(3, "Unhandled code %i", ev->code);
177 static void input_abs(struct GP_InputDriverLinux *self, struct input_event *ev)
179 GP_DEBUG(4, "Absolute event");
181 switch (ev->code) {
182 case ABS_X:
183 self->abs_x = ev->value;
184 self->abs_flag_x = 1;
185 GP_DEBUG(4, "ABS X %i", ev->value);
186 break;
187 case ABS_Y:
188 self->abs_y = ev->value;
189 self->abs_flag_y = 1;
190 GP_DEBUG(4, "ABS Y %i", ev->value);
191 break;
192 case ABS_PRESSURE:
193 self->abs_press = ev->value;
194 break;
195 default:
196 GP_DEBUG(3, "Unhandled code %i", ev->code);
200 static void input_key(struct GP_InputDriverLinux *self,
201 struct GP_EventQueue *event_queue,
202 struct input_event *ev)
204 GP_DEBUG(4, "Key event");
207 * We need to postpone btn touch down until
208 * we read new coordinates for cursor.
210 if (ev->code == BTN_TOUCH) {
211 if (ev->value == 0)
212 self->abs_pen_flag = 1;
213 else
214 return;
217 GP_EventQueuePushKey(event_queue, ev->code, ev->value, NULL);
220 static void do_sync(struct GP_InputDriverLinux *self,
221 struct GP_EventQueue *event_queue)
223 if (self->rel_flag) {
224 self->rel_flag = 0;
225 GP_EventQueuePushRel(event_queue, self->rel_x,
226 self->rel_y, NULL);
227 self->rel_x = 0;
228 self->rel_y = 0;
231 if (self->abs_flag_x || self->abs_flag_y) {
232 uint32_t x = 0, y = 0, x_max = 0, y_max = 0;
234 if (self->abs_flag_x) {
235 /* clipping */
236 if (self->abs_x > self->abs_x_max)
237 self->abs_x = self->abs_x_max;
239 if (self->abs_x < 0)
240 self->abs_x = 0;
242 x = self->abs_x;
243 x_max = self->abs_x_max;
245 self->abs_flag_x = 0;
248 if (self->abs_flag_y) {
249 /* clipping */
250 if (self->abs_y > self->abs_y_max)
251 self->abs_y = self->abs_y_max;
253 if (self->abs_y < 0)
254 self->abs_y = 0;
256 y = self->abs_y;
257 y_max = self->abs_y_max;
259 self->abs_flag_y = 0;
262 GP_EventQueuePushAbs(event_queue, x, y, self->abs_press,
263 x_max, y_max, self->abs_press_max, NULL);
265 self->abs_press = 0;
267 if (self->abs_pen_flag) {
268 GP_EventQueuePushKey(event_queue, BTN_TOUCH, 1, NULL);
269 self->abs_pen_flag = 0;
274 static void input_syn(struct GP_InputDriverLinux *self,
275 struct GP_EventQueue *event_queue,
276 struct input_event *ev)
278 GP_DEBUG(4, "Sync event");
280 switch (ev->code) {
281 case 0:
282 do_sync(self, event_queue);
283 break;
284 default:
285 GP_DEBUG(3, "Unhandled code %i", ev->code);
289 int GP_InputDriverLinuxRead(struct GP_InputDriverLinux *self,
290 struct GP_EventQueue *event_queue)
292 struct input_event ev;
293 int ret;
295 ret = read(self->fd, &ev, sizeof(ev));
297 if (ret == -1 && errno == EAGAIN)
298 return 0;
300 if (ret < 1)
301 return -1;
303 switch (ev.type) {
304 case EV_REL:
305 input_rel(self, &ev);
306 break;
307 case EV_ABS:
308 input_abs(self, &ev);
309 break;
310 case EV_KEY:
311 input_key(self, event_queue, &ev);
312 break;
313 case EV_SYN:
314 input_syn(self, event_queue, &ev);
315 break;
316 default:
317 GP_DEBUG(3, "Unhandled type %i", ev.type);
320 return 1;