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