1 /**
2 * @file lv_evdev.c
3 *
4 */
5
6 /**********************
7 * INCLUDES
8 **********************/
9 #include "lv_evdev_private.h"
10 #if LV_USE_EVDEV
11
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <dirent.h>
18 #include <sys/stat.h>
19 #include <sys/param.h> /*To detect BSD*/
20 #ifdef BSD
21 #include <dev/evdev/input.h>
22 #else
23 #include <linux/input.h>
24 #include <sys/inotify.h>
25 #endif /*BSD*/
26 #include "../../core/lv_global.h"
27 #include "../../misc/lv_types.h"
28 #include "../../misc/lv_assert.h"
29 #include "../../misc/lv_math.h"
30 #include "../../misc/lv_async.h"
31 #include "../../stdlib/lv_mem.h"
32 #include "../../stdlib/lv_string.h"
33 #include "../../display/lv_display.h"
34 #include "../../widgets/image/lv_image.h"
35
36 /*********************
37 * DEFINES
38 *********************/
39
40 #define evdev_discovery LV_GLOBAL_DEFAULT()->evdev_discovery
41 #define EVDEV_DISCOVERY_PATH "/dev/input/"
42 #define EVDEV_DISCOVERY_PATH_BUF_SIZE 32
43 #define REL_XY_MASK ((1 << REL_X) | (1 << REL_Y))
44 #define ABS_XY_MASK ((1 << ABS_X) | (1 << ABS_Y))
45
46 /**********************
47 * TYPEDEFS
48 **********************/
49
50 typedef struct {
51 /*Device*/
52 int fd;
53 dev_t st_dev;
54 ino_t st_ino;
55 lv_evdev_type_t type;
56 /*Config*/
57 bool swap_axes;
58 int min_x;
59 int min_y;
60 int max_x;
61 int max_y;
62 /*State*/
63 int root_x;
64 int root_y;
65 int key;
66 lv_indev_state_t state;
67 bool deleting;
68 } lv_evdev_t;
69
70 #ifndef BSD
71 struct _lv_evdev_discovery_t {
72 lv_evdev_discovery_cb_t cb;
73 void * cb_user_data;
74 int inotify_fd;
75 bool inotify_watch_active;
76 lv_timer_t * timer;
77 };
78 #endif
79
80 /**********************
81 * STATIC FUNCTIONS
82 **********************/
83
_evdev_process_key(uint16_t code)84 static int _evdev_process_key(uint16_t code)
85 {
86 switch(code) {
87 case KEY_UP:
88 return LV_KEY_UP;
89 case KEY_DOWN:
90 return LV_KEY_DOWN;
91 case KEY_RIGHT:
92 return LV_KEY_RIGHT;
93 case KEY_LEFT:
94 return LV_KEY_LEFT;
95 case KEY_ESC:
96 return LV_KEY_ESC;
97 case KEY_DELETE:
98 return LV_KEY_DEL;
99 case KEY_BACKSPACE:
100 return LV_KEY_BACKSPACE;
101 case KEY_ENTER:
102 return LV_KEY_ENTER;
103 case KEY_NEXT:
104 case KEY_TAB:
105 return LV_KEY_NEXT;
106 case KEY_PREVIOUS:
107 return LV_KEY_PREV;
108 case KEY_HOME:
109 return LV_KEY_HOME;
110 case KEY_END:
111 return LV_KEY_END;
112 default:
113 return 0;
114 }
115 }
116
_evdev_calibrate(int v,int in_min,int in_max,int out_min,int out_max)117 static int _evdev_calibrate(int v, int in_min, int in_max, int out_min, int out_max)
118 {
119 if(in_min != in_max) v = (v - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
120 return LV_CLAMP(out_min, v, out_max);
121 }
122
_evdev_process_pointer(lv_indev_t * indev,int x,int y)123 static lv_point_t _evdev_process_pointer(lv_indev_t * indev, int x, int y)
124 {
125 lv_display_t * disp = lv_indev_get_display(indev);
126 lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
127 LV_ASSERT_NULL(dsc);
128
129 int swapped_x = dsc->swap_axes ? y : x;
130 int swapped_y = dsc->swap_axes ? x : y;
131
132 int offset_x = lv_display_get_offset_x(disp);
133 int offset_y = lv_display_get_offset_y(disp);
134 int width = lv_display_get_horizontal_resolution(disp);
135 int height = lv_display_get_vertical_resolution(disp);
136
137 lv_point_t p;
138 p.x = _evdev_calibrate(swapped_x, dsc->min_x, dsc->max_x, offset_x, offset_x + width - 1);
139 p.y = _evdev_calibrate(swapped_y, dsc->min_y, dsc->max_y, offset_y, offset_y + height - 1);
140 return p;
141 }
142
_evdev_async_delete_cb(void * user_data)143 static void _evdev_async_delete_cb(void * user_data)
144 {
145 lv_indev_t * indev = user_data;
146 lv_indev_delete(indev);
147 }
148
_evdev_read(lv_indev_t * indev,lv_indev_data_t * data)149 static void _evdev_read(lv_indev_t * indev, lv_indev_data_t * data)
150 {
151 lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
152 LV_ASSERT_NULL(dsc);
153
154 /*Update dsc with buffered events*/
155 struct input_event in = { 0 };
156 ssize_t br;
157 while((br = read(dsc->fd, &in, sizeof(in))) > 0) {
158 if(in.type == EV_REL) {
159 if(in.code == REL_X) dsc->root_x += in.value;
160 else if(in.code == REL_Y) dsc->root_y += in.value;
161 }
162 else if(in.type == EV_ABS) {
163 if(in.code == ABS_X || in.code == ABS_MT_POSITION_X) dsc->root_x = in.value;
164 else if(in.code == ABS_Y || in.code == ABS_MT_POSITION_Y) dsc->root_y = in.value;
165 else if(in.code == ABS_MT_TRACKING_ID) {
166 if(in.value == -1) dsc->state = LV_INDEV_STATE_RELEASED;
167 else if(in.value == 0) dsc->state = LV_INDEV_STATE_PRESSED;
168 }
169 }
170 else if(in.type == EV_KEY) {
171 if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) {
172 if(in.value == 0) dsc->state = LV_INDEV_STATE_RELEASED;
173 else if(in.value == 1) dsc->state = LV_INDEV_STATE_PRESSED;
174 }
175 else {
176 dsc->key = _evdev_process_key(in.code);
177 if(dsc->key) {
178 dsc->state = in.value ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
179 data->continue_reading = true; /*Keep following events in buffer for now*/
180 break;
181 }
182 }
183 }
184 }
185 if(!dsc->deleting && br == -1 && errno != EAGAIN) {
186 if(errno == ENODEV) {
187 LV_LOG_INFO("evdev device was removed");
188 }
189 else {
190 LV_LOG_ERROR("read failed: %s", strerror(errno));
191 }
192 lv_async_call(_evdev_async_delete_cb, indev);
193 dsc->deleting = true;
194 }
195
196 /*Process and store in data*/
197 switch(lv_indev_get_type(indev)) {
198 case LV_INDEV_TYPE_KEYPAD:
199 data->state = dsc->state;
200 data->key = dsc->key;
201 break;
202 case LV_INDEV_TYPE_POINTER:
203 data->state = dsc->state;
204 data->point = _evdev_process_pointer(indev, dsc->root_x, dsc->root_y);
205 break;
206 default:
207 break;
208 }
209 }
210
_evdev_indev_delete_cb(lv_event_t * e)211 static void _evdev_indev_delete_cb(lv_event_t * e)
212 {
213 lv_indev_t * indev = lv_event_get_target(e);
214 lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
215 LV_ASSERT_NULL(dsc);
216 lv_async_call_cancel(_evdev_async_delete_cb, indev);
217 close(dsc->fd);
218 lv_free(dsc);
219 }
220
221 #ifndef BSD
_evdev_discovery_indev_try_create(const char * file_name)222 static void _evdev_discovery_indev_try_create(const char * file_name)
223 {
224 if(0 != lv_strncmp(file_name, "event", 5)) {
225 return;
226 }
227
228 char dev_path[EVDEV_DISCOVERY_PATH_BUF_SIZE];
229 lv_snprintf(dev_path, sizeof(dev_path), EVDEV_DISCOVERY_PATH "%s", file_name);
230
231 lv_indev_t * indev = lv_evdev_create(LV_INDEV_TYPE_NONE, dev_path);
232 if(indev == NULL) return;
233
234 lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
235
236 /* Compare this new evdev's unique identity with the already registered ones.
237 * If a match is found, it means the user has already added it and a duplicate
238 * should not be added automatically -- although it is valid for `lv_evdev_create`
239 * to be explicitly called with the same path by the user -- or an edge case
240 * has occurred where discoverey has just been started and a new device was
241 * connected between the creation of the inotify watcher and the initial full
242 * scan of the directory with `readdir`.
243 */
244 lv_indev_t * ex_indev = NULL;
245 while(NULL != (ex_indev = lv_indev_get_next(ex_indev))) {
246 if(ex_indev == indev || lv_indev_get_read_cb(ex_indev) != _evdev_read) continue;
247 lv_evdev_t * ex_dsc = lv_indev_get_driver_data(ex_indev);
248 if(!ex_dsc->deleting && dsc->st_dev == ex_dsc->st_dev && dsc->st_ino == ex_dsc->st_ino) {
249 /* an indev for this exact device instance already exists */
250 lv_indev_delete(indev);
251 return;
252 }
253 }
254
255 lv_evdev_discovery_t * ed = evdev_discovery;
256 if(ed->cb) {
257 ed->cb(indev, dsc->type, ed->cb_user_data);
258 }
259 }
260
_evdev_discovery_inotify_try_init_watcher(int inotify_fd)261 static bool _evdev_discovery_inotify_try_init_watcher(int inotify_fd)
262 {
263 int inotify_wd = inotify_add_watch(inotify_fd, EVDEV_DISCOVERY_PATH, IN_CREATE);
264 if(inotify_wd == -1) {
265 if(errno != ENOENT) {
266 LV_LOG_ERROR("inotify_add_watch failed: %s", strerror(errno));
267 }
268 return false;
269 }
270
271 DIR * dir = opendir(EVDEV_DISCOVERY_PATH);
272 if(dir == NULL) {
273 if(errno != ENOENT) {
274 LV_LOG_ERROR("opendir failed: %s", strerror(errno));
275 }
276 inotify_rm_watch(inotify_fd, inotify_wd);
277 return false;
278 }
279 while(1) {
280 struct dirent * dirent = readdir(dir);
281 if(dirent == NULL) break; /* only possible error is EBADF, so no errno check needed */
282 _evdev_discovery_indev_try_create(dirent->d_name);
283 if(evdev_discovery == NULL) {
284 /* was stopped by the callback. cleanup was already done */
285 closedir(dir);
286 return false;
287 }
288 }
289 closedir(dir);
290
291 return true;
292 }
293
_evdev_discovery_timer_cb(lv_timer_t * tim)294 static void _evdev_discovery_timer_cb(lv_timer_t * tim)
295 {
296 lv_evdev_discovery_t * ed = evdev_discovery;
297 LV_ASSERT_NULL(ed);
298
299 if(!ed->inotify_watch_active) {
300 ed->inotify_watch_active = _evdev_discovery_inotify_try_init_watcher(ed->inotify_fd);
301 return;
302 }
303
304 union {
305 struct inotify_event in_ev;
306 uint8_t buf[sizeof(struct inotify_event) + NAME_MAX + 1];
307 } in_data;
308 ssize_t br;
309 while((br = read(ed->inotify_fd, &in_data, sizeof(in_data))) > 0) {
310 struct inotify_event * in_ev_p;
311 for(uint8_t * in_data_buf_p = in_data.buf;
312 in_data_buf_p < in_data.buf + br;
313 in_data_buf_p += sizeof(struct inotify_event) + in_ev_p->len) {
314 in_ev_p = (struct inotify_event *)in_data_buf_p;
315 if(in_ev_p->mask & IN_IGNORED) {
316 /* /dev/input/ was deleted because the last device was removed.
317 * The watch was removed implicitly. It will try to be
318 * recreated the next time the timer runs.
319 */
320 ed->inotify_watch_active = false;
321 return;
322 }
323 if(!(in_ev_p->mask & IN_ISDIR) && in_ev_p->len) {
324 _evdev_discovery_indev_try_create(in_ev_p->name);
325 if(evdev_discovery == NULL) return; /* was stopped by the callback */
326 }
327 }
328 }
329 if(br == -1 && errno != EAGAIN) {
330 LV_LOG_ERROR("inotify read failed: %s", strerror(errno));
331 lv_evdev_discovery_stop();
332 }
333 }
334 #endif /*BSD*/
335
336 /**********************
337 * GLOBAL FUNCTIONS
338 **********************/
339
lv_evdev_create(lv_indev_type_t indev_type,const char * dev_path)340 lv_indev_t * lv_evdev_create(lv_indev_type_t indev_type, const char * dev_path)
341 {
342 lv_evdev_t * dsc = lv_malloc_zeroed(sizeof(lv_evdev_t));
343 LV_ASSERT_MALLOC(dsc);
344 if(dsc == NULL) return NULL;
345
346 dsc->fd = open(dev_path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
347 if(dsc->fd < 0) {
348 LV_LOG_WARN("open failed: %s", strerror(errno));
349 goto err_after_malloc;
350 }
351
352 struct stat sb;
353 if(0 != fstat(dsc->fd, &sb)) {
354 LV_LOG_ERROR("fstat failed: %s", strerror(errno));
355 goto err_after_open;
356 }
357 dsc->st_dev = sb.st_dev;
358 dsc->st_ino = sb.st_ino;
359
360 if(indev_type == LV_INDEV_TYPE_NONE) {
361 uint32_t rel_bits = 0;
362 if(ioctl(dsc->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), &rel_bits) >= 0) {
363 /* if this device can emit relative X and Y events, it shall be a pointer indev */
364 if((rel_bits & REL_XY_MASK) == REL_XY_MASK) {
365 indev_type = LV_INDEV_TYPE_POINTER;
366 dsc->type = LV_EVDEV_TYPE_REL;
367 }
368 }
369 else {
370 LV_LOG_WARN("ioctl EVIOCGBIT(EV_REL, ...) failed: %s", strerror(errno));
371 }
372 }
373
374 if(indev_type == LV_INDEV_TYPE_NONE) {
375 uint32_t abs_bits = 0;
376 if(ioctl(dsc->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), &abs_bits) >= 0) {
377 /* if this device can emit absolute X and Y events, it shall be a pointer indev */
378 if((abs_bits & ABS_XY_MASK) == ABS_XY_MASK) {
379 indev_type = LV_INDEV_TYPE_POINTER;
380 dsc->type = LV_EVDEV_TYPE_ABS;
381 }
382 }
383 else {
384 LV_LOG_WARN("ioctl EVIOCGBIT(EV_ABS, ...) failed: %s", strerror(errno));
385 }
386 }
387
388 if(indev_type == LV_INDEV_TYPE_NONE) {
389 uint32_t key_bits[KEY_MAX / 32 + 1] = {0};
390 if(ioctl(dsc->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) >= 0) {
391 /* if this device can emit any key events, it shall be a keypad indev */
392 for(int32_t i = 0; i < (int32_t)(sizeof(key_bits) / sizeof(uint32_t)); i++) {
393 if(key_bits[i]) {
394 indev_type = LV_INDEV_TYPE_KEYPAD;
395 dsc->type = LV_EVDEV_TYPE_KEY;
396 break;
397 }
398 }
399 }
400 else {
401 LV_LOG_WARN("ioctl EVIOCGBIT(EV_KEY, ...) failed: %s", strerror(errno));
402 }
403 }
404
405 if(indev_type == LV_INDEV_TYPE_NONE) {
406 goto err_after_open;
407 }
408
409 if(fcntl(dsc->fd, F_SETFL, O_NONBLOCK) < 0) {
410 LV_LOG_ERROR("fcntl failed: %s", strerror(errno));
411 goto err_after_open;
412 }
413
414 /* Detect the minimum and maximum values of the input device for calibration. */
415
416 if(indev_type == LV_INDEV_TYPE_POINTER) {
417 struct input_absinfo absinfo;
418 if(ioctl(dsc->fd, EVIOCGABS(ABS_X), &absinfo) == 0) {
419 dsc->min_x = absinfo.minimum;
420 dsc->max_x = absinfo.maximum;
421 }
422 else {
423 LV_LOG_INFO("ioctl EVIOCGABS(ABS_X) failed: %s", strerror(errno));
424 }
425 if(ioctl(dsc->fd, EVIOCGABS(ABS_Y), &absinfo) == 0) {
426 dsc->min_y = absinfo.minimum;
427 dsc->max_y = absinfo.maximum;
428 }
429 else {
430 LV_LOG_INFO("ioctl EVIOCGABS(ABS_Y) failed: %s", strerror(errno));
431 }
432 }
433
434 lv_indev_t * indev = lv_indev_create();
435 if(indev == NULL) goto err_after_open;
436 lv_indev_set_type(indev, indev_type);
437 lv_indev_set_read_cb(indev, _evdev_read);
438 lv_indev_set_driver_data(indev, dsc);
439 lv_indev_add_event_cb(indev, _evdev_indev_delete_cb, LV_EVENT_DELETE, NULL);
440
441 return indev;
442
443 err_after_open:
444 close(dsc->fd);
445 err_after_malloc:
446 lv_free(dsc);
447 return NULL;
448 }
449
lv_evdev_discovery_start(lv_evdev_discovery_cb_t cb,void * user_data)450 lv_result_t lv_evdev_discovery_start(lv_evdev_discovery_cb_t cb, void * user_data)
451 {
452 #ifndef BSD
453 lv_evdev_discovery_t * ed = NULL;
454 int inotify_fd = -1;
455 lv_timer_t * timer = NULL;
456
457 ed = lv_malloc_zeroed(sizeof(lv_evdev_discovery_t));
458 LV_ASSERT_MALLOC(ed);
459 if(ed == NULL) return LV_RESULT_INVALID;
460 evdev_discovery = ed;
461
462 ed->cb = cb;
463 ed->cb_user_data = user_data;
464
465 inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
466 if(inotify_fd == -1) {
467 LV_LOG_ERROR("inotify_init1 failed: %s", strerror(errno));
468 goto err_out;
469 }
470 ed->inotify_fd = inotify_fd;
471
472 ed->inotify_watch_active = _evdev_discovery_inotify_try_init_watcher(inotify_fd);
473 if(evdev_discovery == NULL) return LV_RESULT_OK; /* was stopped by the callback. cleanup was already done */
474
475 timer = lv_timer_create(_evdev_discovery_timer_cb, LV_DEF_REFR_PERIOD, NULL);
476 if(timer == NULL) goto err_out;
477 ed->timer = timer;
478
479 return LV_RESULT_OK;
480
481 err_out:
482 if(timer != NULL) lv_timer_delete(timer);
483 if(inotify_fd != -1) close(inotify_fd);
484 lv_free(ed);
485 evdev_discovery = NULL;
486 return LV_RESULT_INVALID;
487
488 #else /*BSD*/
489 return LV_RESULT_INVALID;
490 #endif
491 }
492
lv_evdev_discovery_stop(void)493 lv_result_t lv_evdev_discovery_stop(void)
494 {
495 #ifndef BSD
496 lv_evdev_discovery_t * ed = evdev_discovery;
497 if(ed == NULL) return LV_RESULT_INVALID;
498
499 if(ed->timer) lv_timer_delete(ed->timer);
500 close(ed->inotify_fd);
501 lv_free(ed);
502
503 evdev_discovery = NULL;
504 return LV_RESULT_OK;
505 #else
506 return LV_RESULT_INVALID;
507 #endif
508 }
509
lv_evdev_set_swap_axes(lv_indev_t * indev,bool swap_axes)510 void lv_evdev_set_swap_axes(lv_indev_t * indev, bool swap_axes)
511 {
512 lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
513 LV_ASSERT_NULL(dsc);
514 dsc->swap_axes = swap_axes;
515 }
516
lv_evdev_set_calibration(lv_indev_t * indev,int min_x,int min_y,int max_x,int max_y)517 void lv_evdev_set_calibration(lv_indev_t * indev, int min_x, int min_y, int max_x, int max_y)
518 {
519 lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
520 LV_ASSERT_NULL(dsc);
521 dsc->min_x = min_x;
522 dsc->min_y = min_y;
523 dsc->max_x = max_x;
524 dsc->max_y = max_y;
525 }
526
lv_evdev_delete(lv_indev_t * indev)527 void lv_evdev_delete(lv_indev_t * indev)
528 {
529 lv_indev_delete(indev);
530 }
531
lv_evdev_deinit(void)532 void lv_evdev_deinit(void)
533 {
534 lv_evdev_discovery_stop();
535 }
536
537 #endif /*LV_USE_EVDEV*/
538