diff --git a/docs/details/integration/driver/touchpad/evdev.rst b/docs/details/integration/driver/touchpad/evdev.rst index 3dc2c6bb9..a2e0eeda3 100644 --- a/docs/details/integration/driver/touchpad/evdev.rst +++ b/docs/details/integration/driver/touchpad/evdev.rst @@ -20,7 +20,7 @@ Enable the Linux LVGL evdev driver support in ``lv_conf.h``. .. code-block:: c - #define LV_USE_EVDEV 1 + #define LV_USE_EVDEV 1 Usage ----- @@ -30,15 +30,15 @@ Then link this to the LVGL display with ``lv_indev_set_display``. .. code-block:: c - lv_indev_t *touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0"); - lv_indev_set_display(touch, disp); + lv_indev_t *touch = lv_evdev_create(LV_INDEV_TYPE_POINTER, "/dev/input/event0"); + lv_indev_set_display(touch, disp); Ensure that an ``lv_display_t`` object is already created for ``disp``. An example for this is shown below, using the Linux framebuffer driver. .. code-block:: c - lv_display_t * disp = lv_linux_fbdev - lv_linux_fbdev_set_file(disp, "/dev/fb0");_create(); + lv_display_t * disp = lv_linux_fbdev + lv_linux_fbdev_set_file(disp, "/dev/fb0");_create(); Locating your input device @@ -55,3 +55,48 @@ You can use ``evtest`` to show data from that event source to see if it is actua Try: ``$evtest /dev/input/event1`` replacing ``eventX`` with your event device from above. + +Automatic input device discovery +-------------------------------- + +There is support for automatically finding and adding input devices in ``/dev/input/``. New devices will automatically be added +when they are connected. To enable this feature, you can simply call :cpp:expr:`lv_evdev_discovery_start(NULL, NULL)`. + +You may want to react to a new device being added so that a cursor image can be applied, for example. You can provide a callback +function which will be called when a new device is added. + +.. code-block:: c + + #include "lvgl/src/core/lv_global.h" + + static void indev_deleted_cb(lv_event_t * e) + { + if(LV_GLOBAL_DEFAULT()->deinit_in_progress) return; + lv_obj_t * cursor_obj = lv_event_get_user_data(e) + lv_obj_delete(cursor_obj); + } + + static void discovery_cb(lv_indev_t * indev, lv_evdev_type_t type, void * user_data) + { + LV_LOG_USER("new '%s' device discovered", type == LV_EVDEV_TYPE_REL ? "REL" : + type == LV_EVDEV_TYPE_ABS ? "ABS" : + type == LV_EVDEV_TYPE_KEY ? "KEY" : + "unknown"); + + if(type == LV_EVDEV_TYPE_REL) { + LV_IMAGE_DECLARE(mouse_cursor_icon); + lv_obj_t * cursor_obj = lv_image_create(lv_screen_active()); + lv_image_set_src(cursor_obj, &mouse_cursor_icon); + lv_indev_set_cursor(indev, cursor_obj); + lv_indev_add_event_cb(indev, indev_deleted_cb, LV_EVENT_DELETE, cursor_obj); + } + } + + int main() + { + /* ... */ + lv_evdev_discovery_start(discovery_cb, NULL); + /* ... */ + } + +At the time of writing, this feature is not supported in BSD. diff --git a/lvgl_private.h b/lvgl_private.h index b4a958c83..415d3f6d1 100644 --- a/lvgl_private.h +++ b/lvgl_private.h @@ -47,6 +47,7 @@ extern "C" { #include "src/draw/sw/blend/lv_draw_sw_blend_private.h" #include "src/drivers/libinput/lv_xkb_private.h" #include "src/drivers/libinput/lv_libinput_private.h" +#include "src/drivers/evdev/lv_evdev_private.h" #include "src/font/lv_font_fmt_txt_private.h" #include "src/themes/lv_theme_private.h" #include "src/core/lv_refr_private.h" diff --git a/src/core/lv_global.h b/src/core/lv_global.h index 52a643158..9428dae2f 100644 --- a/src/core/lv_global.h +++ b/src/core/lv_global.h @@ -233,6 +233,9 @@ typedef struct _lv_global_t { bool freertos_idle_task_running; #endif +#if LV_USE_EVDEV + lv_evdev_discovery_t * evdev_discovery; +#endif void * user_data; } lv_global_t; diff --git a/src/drivers/evdev/lv_evdev.c b/src/drivers/evdev/lv_evdev.c index e7d31ecff..e5a990e27 100644 --- a/src/drivers/evdev/lv_evdev.c +++ b/src/drivers/evdev/lv_evdev.c @@ -6,24 +6,42 @@ /********************** * INCLUDES **********************/ -#include "lv_evdev.h" +#include "lv_evdev_private.h" #if LV_USE_EVDEV #include #include #include #include +#include +#include +#include #include /*To detect BSD*/ #ifdef BSD #include #else #include + #include #endif /*BSD*/ +#include "../../core/lv_global.h" +#include "../../misc/lv_types.h" #include "../../misc/lv_assert.h" #include "../../misc/lv_math.h" +#include "../../misc/lv_async.h" #include "../../stdlib/lv_mem.h" #include "../../stdlib/lv_string.h" #include "../../display/lv_display.h" +#include "../../widgets/image/lv_image.h" + +/********************* + * DEFINES + *********************/ + +#define evdev_discovery LV_GLOBAL_DEFAULT()->evdev_discovery +#define EVDEV_DISCOVERY_PATH "/dev/input/" +#define EVDEV_DISCOVERY_PATH_BUF_SIZE 32 +#define REL_XY_MASK ((1 << REL_X) | (1 << REL_Y)) +#define ABS_XY_MASK ((1 << ABS_X) | (1 << ABS_Y)) /********************** * TYPEDEFS @@ -32,6 +50,9 @@ typedef struct { /*Device*/ int fd; + dev_t st_dev; + ino_t st_ino; + lv_evdev_type_t type; /*Config*/ bool swap_axes; int min_x; @@ -43,8 +64,19 @@ typedef struct { int root_y; int key; lv_indev_state_t state; + bool deleting; } lv_evdev_t; +#ifndef BSD +struct _lv_evdev_discovery_t { + lv_evdev_discovery_cb_t cb; + void * cb_user_data; + int inotify_fd; + bool inotify_watch_active; + lv_timer_t * timer; +}; +#endif + /********************** * STATIC FUNCTIONS **********************/ @@ -108,6 +140,12 @@ static lv_point_t _evdev_process_pointer(lv_indev_t * indev, int x, int y) return p; } +static void _evdev_async_delete_cb(void * user_data) +{ + lv_indev_t * indev = user_data; + lv_indev_delete(indev); +} + static void _evdev_read(lv_indev_t * indev, lv_indev_data_t * data) { lv_evdev_t * dsc = lv_indev_get_driver_data(indev); @@ -115,7 +153,8 @@ static void _evdev_read(lv_indev_t * indev, lv_indev_data_t * data) /*Update dsc with buffered events*/ struct input_event in = { 0 }; - while(read(dsc->fd, &in, sizeof(in)) > 0) { + ssize_t br; + while((br = read(dsc->fd, &in, sizeof(in))) > 0) { if(in.type == EV_REL) { if(in.code == REL_X) dsc->root_x += in.value; else if(in.code == REL_Y) dsc->root_y += in.value; @@ -143,6 +182,16 @@ static void _evdev_read(lv_indev_t * indev, lv_indev_data_t * data) } } } + if(!dsc->deleting && br == -1 && errno != EAGAIN) { + if(errno == ENODEV) { + LV_LOG_INFO("evdev device was removed"); + } + else { + LV_LOG_ERROR("read failed: %s", strerror(errno)); + } + lv_async_call(_evdev_async_delete_cb, indev); + dsc->deleting = true; + } /*Process and store in data*/ switch(lv_indev_get_type(indev)) { @@ -159,6 +208,131 @@ static void _evdev_read(lv_indev_t * indev, lv_indev_data_t * data) } } +static void _evdev_indev_delete_cb(lv_event_t * e) +{ + lv_indev_t * indev = lv_event_get_target(e); + lv_evdev_t * dsc = lv_indev_get_driver_data(indev); + LV_ASSERT_NULL(dsc); + lv_async_call_cancel(_evdev_async_delete_cb, indev); + close(dsc->fd); + lv_free(dsc); +} + +#ifndef BSD +static void _evdev_discovery_indev_try_create(const char * file_name) +{ + if(0 != lv_strncmp(file_name, "event", 5)) { + return; + } + + char dev_path[EVDEV_DISCOVERY_PATH_BUF_SIZE]; + lv_snprintf(dev_path, sizeof(dev_path), EVDEV_DISCOVERY_PATH "%s", file_name); + + lv_indev_t * indev = lv_evdev_create(LV_INDEV_TYPE_NONE, dev_path); + if(indev == NULL) return; + + lv_evdev_t * dsc = lv_indev_get_driver_data(indev); + + /* Compare this new evdev's unique identity with the already registered ones. + * If a match is found, it means the user has already added it and a duplicate + * should not be added automatically -- although it is valid for `lv_evdev_create` + * to be explicitly called with the same path by the user -- or an edge case + * has occurred where discoverey has just been started and a new device was + * connected between the creation of the inotify watcher and the initial full + * scan of the directory with `readdir`. + */ + lv_indev_t * ex_indev = NULL; + while(NULL != (ex_indev = lv_indev_get_next(ex_indev))) { + if(ex_indev == indev || lv_indev_get_read_cb(ex_indev) != _evdev_read) continue; + lv_evdev_t * ex_dsc = lv_indev_get_driver_data(ex_indev); + if(!ex_dsc->deleting && dsc->st_dev == ex_dsc->st_dev && dsc->st_ino == ex_dsc->st_ino) { + /* an indev for this exact device instance already exists */ + lv_indev_delete(indev); + return; + } + } + + lv_evdev_discovery_t * ed = evdev_discovery; + if(ed->cb) { + ed->cb(indev, dsc->type, ed->cb_user_data); + } +} + +static bool _evdev_discovery_inotify_try_init_watcher(int inotify_fd) +{ + int inotify_wd = inotify_add_watch(inotify_fd, EVDEV_DISCOVERY_PATH, IN_CREATE); + if(inotify_wd == -1) { + if(errno != ENOENT) { + LV_LOG_ERROR("inotify_add_watch failed: %s", strerror(errno)); + } + return false; + } + + DIR * dir = opendir(EVDEV_DISCOVERY_PATH); + if(dir == NULL) { + if(errno != ENOENT) { + LV_LOG_ERROR("opendir failed: %s", strerror(errno)); + } + inotify_rm_watch(inotify_fd, inotify_wd); + return false; + } + while(1) { + struct dirent * dirent = readdir(dir); + if(dirent == NULL) break; /* only possible error is EBADF, so no errno check needed */ + _evdev_discovery_indev_try_create(dirent->d_name); + if(evdev_discovery == NULL) { + /* was stopped by the callback. cleanup was already done */ + closedir(dir); + return false; + } + } + closedir(dir); + + return true; +} + +static void _evdev_discovery_timer_cb(lv_timer_t * tim) +{ + lv_evdev_discovery_t * ed = evdev_discovery; + LV_ASSERT_NULL(ed); + + if(!ed->inotify_watch_active) { + ed->inotify_watch_active = _evdev_discovery_inotify_try_init_watcher(ed->inotify_fd); + return; + } + + union { + struct inotify_event in_ev; + uint8_t buf[sizeof(struct inotify_event) + NAME_MAX + 1]; + } in_data; + ssize_t br; + while((br = read(ed->inotify_fd, &in_data, sizeof(in_data))) > 0) { + struct inotify_event * in_ev_p; + for(uint8_t * in_data_buf_p = in_data.buf; + in_data_buf_p < in_data.buf + br; + in_data_buf_p += sizeof(struct inotify_event) + in_ev_p->len) { + in_ev_p = (struct inotify_event *)in_data_buf_p; + if(in_ev_p->mask & IN_IGNORED) { + /* /dev/input/ was deleted because the last device was removed. + * The watch was removed implicitly. It will try to be + * recreated the next time the timer runs. + */ + ed->inotify_watch_active = false; + return; + } + if(!(in_ev_p->mask & IN_ISDIR) && in_ev_p->len) { + _evdev_discovery_indev_try_create(in_ev_p->name); + if(evdev_discovery == NULL) return; /* was stopped by the callback */ + } + } + } + if(br == -1 && errno != EAGAIN) { + LV_LOG_ERROR("inotify read failed: %s", strerror(errno)); + lv_evdev_discovery_stop(); + } +} +#endif /*BSD*/ + /********************** * GLOBAL FUNCTIONS **********************/ @@ -171,10 +345,67 @@ lv_indev_t * lv_evdev_create(lv_indev_type_t indev_type, const char * dev_path) dsc->fd = open(dev_path, O_RDONLY | O_NOCTTY | O_CLOEXEC); if(dsc->fd < 0) { - LV_LOG_ERROR("open failed: %s", strerror(errno)); + LV_LOG_WARN("open failed: %s", strerror(errno)); goto err_after_malloc; } + struct stat sb; + if(0 != fstat(dsc->fd, &sb)) { + LV_LOG_ERROR("fstat failed: %s", strerror(errno)); + goto err_after_open; + } + dsc->st_dev = sb.st_dev; + dsc->st_ino = sb.st_ino; + + if(indev_type == LV_INDEV_TYPE_NONE) { + uint32_t rel_bits = 0; + if(ioctl(dsc->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), &rel_bits) >= 0) { + /* if this device can emit relative X and Y events, it shall be a pointer indev */ + if((rel_bits & REL_XY_MASK) == REL_XY_MASK) { + indev_type = LV_INDEV_TYPE_POINTER; + dsc->type = LV_EVDEV_TYPE_REL; + } + } + else { + LV_LOG_WARN("ioctl EVIOCGBIT(EV_REL, ...) failed: %s", strerror(errno)); + } + } + + if(indev_type == LV_INDEV_TYPE_NONE) { + uint32_t abs_bits = 0; + if(ioctl(dsc->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), &abs_bits) >= 0) { + /* if this device can emit absolute X and Y events, it shall be a pointer indev */ + if((abs_bits & ABS_XY_MASK) == ABS_XY_MASK) { + indev_type = LV_INDEV_TYPE_POINTER; + dsc->type = LV_EVDEV_TYPE_ABS; + } + } + else { + LV_LOG_WARN("ioctl EVIOCGBIT(EV_ABS, ...) failed: %s", strerror(errno)); + } + } + + if(indev_type == LV_INDEV_TYPE_NONE) { + uint32_t key_bits[KEY_MAX / 32 + 1] = {0}; + if(ioctl(dsc->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) >= 0) { + /* if this device can emit any key events, it shall be a keypad indev */ + for(int32_t i = 0; i < (int32_t)(sizeof(key_bits) / sizeof(uint32_t)); i++) { + if(key_bits[i]) { + indev_type = LV_INDEV_TYPE_KEYPAD; + dsc->type = LV_EVDEV_TYPE_KEY; + break; + } + } + } + else { + LV_LOG_WARN("ioctl EVIOCGBIT(EV_KEY, ...) failed: %s", strerror(errno)); + } + } + + if(indev_type == LV_INDEV_TYPE_NONE) { + goto err_after_open; + } + if(fcntl(dsc->fd, F_SETFL, O_NONBLOCK) < 0) { LV_LOG_ERROR("fcntl failed: %s", strerror(errno)); goto err_after_open; @@ -189,14 +420,14 @@ lv_indev_t * lv_evdev_create(lv_indev_type_t indev_type, const char * dev_path) dsc->max_x = absinfo.maximum; } else { - LV_LOG_ERROR("ioctl EVIOCGABS(ABS_X) failed: %s", strerror(errno)); + LV_LOG_INFO("ioctl EVIOCGABS(ABS_X) failed: %s", strerror(errno)); } if(ioctl(dsc->fd, EVIOCGABS(ABS_Y), &absinfo) == 0) { dsc->min_y = absinfo.minimum; dsc->max_y = absinfo.maximum; } else { - LV_LOG_ERROR("ioctl EVIOCGABS(ABS_Y) failed: %s", strerror(errno)); + LV_LOG_INFO("ioctl EVIOCGABS(ABS_Y) failed: %s", strerror(errno)); } } @@ -205,6 +436,8 @@ lv_indev_t * lv_evdev_create(lv_indev_type_t indev_type, const char * dev_path) lv_indev_set_type(indev, indev_type); lv_indev_set_read_cb(indev, _evdev_read); lv_indev_set_driver_data(indev, dsc); + lv_indev_add_event_cb(indev, _evdev_indev_delete_cb, LV_EVENT_DELETE, NULL); + return indev; err_after_open: @@ -214,6 +447,66 @@ err_after_malloc: return NULL; } +lv_result_t lv_evdev_discovery_start(lv_evdev_discovery_cb_t cb, void * user_data) +{ +#ifndef BSD + lv_evdev_discovery_t * ed = NULL; + int inotify_fd = -1; + lv_timer_t * timer = NULL; + + ed = lv_malloc_zeroed(sizeof(lv_evdev_discovery_t)); + LV_ASSERT_MALLOC(ed); + if(ed == NULL) return LV_RESULT_INVALID; + evdev_discovery = ed; + + ed->cb = cb; + ed->cb_user_data = user_data; + + inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); + if(inotify_fd == -1) { + LV_LOG_ERROR("inotify_init1 failed: %s", strerror(errno)); + goto err_out; + } + ed->inotify_fd = inotify_fd; + + ed->inotify_watch_active = _evdev_discovery_inotify_try_init_watcher(inotify_fd); + if(evdev_discovery == NULL) return LV_RESULT_OK; /* was stopped by the callback. cleanup was already done */ + + timer = lv_timer_create(_evdev_discovery_timer_cb, LV_DEF_REFR_PERIOD, NULL); + if(timer == NULL) goto err_out; + ed->timer = timer; + + return LV_RESULT_OK; + +err_out: + if(timer != NULL) lv_timer_delete(timer); + if(inotify_fd != -1) close(inotify_fd); + lv_free(ed); + evdev_discovery = NULL; + return LV_RESULT_INVALID; + +#else /*BSD*/ + return LV_RESULT_INVALID; +#endif +} + +lv_result_t lv_evdev_discovery_stop(void) +{ +#ifndef BSD + lv_evdev_discovery_t * ed = evdev_discovery; + if(ed == NULL) return LV_RESULT_INVALID; + + if(ed->timer) lv_timer_delete(ed->timer); + close(ed->inotify_fd); + lv_free(ed); + + evdev_discovery = NULL; + return LV_RESULT_OK; +#else + return LV_RESULT_INVALID; +#endif +} + void lv_evdev_set_swap_axes(lv_indev_t * indev, bool swap_axes) { lv_evdev_t * dsc = lv_indev_get_driver_data(indev); @@ -233,12 +526,12 @@ void lv_evdev_set_calibration(lv_indev_t * indev, int min_x, int min_y, int max_ void lv_evdev_delete(lv_indev_t * indev) { - lv_evdev_t * dsc = lv_indev_get_driver_data(indev); - LV_ASSERT_NULL(dsc); - close(dsc->fd); - lv_free(dsc); - lv_indev_delete(indev); } +void lv_evdev_deinit(void) +{ + lv_evdev_discovery_stop(); +} + #endif /*LV_USE_EVDEV*/ diff --git a/src/drivers/evdev/lv_evdev.h b/src/drivers/evdev/lv_evdev.h index 95ab1544c..091de6717 100644 --- a/src/drivers/evdev/lv_evdev.h +++ b/src/drivers/evdev/lv_evdev.h @@ -18,6 +18,23 @@ extern "C" { #if LV_USE_EVDEV +/********************** + * TYPEDEFS + **********************/ + +typedef enum { + LV_EVDEV_TYPE_REL, /**< mice */ + LV_EVDEV_TYPE_ABS, /**< touch screens, mousepads */ + LV_EVDEV_TYPE_KEY /**< keyboards, keypads, buttons */ +} lv_evdev_type_t; + +/** + * @param indev the indev created for the newly discovered evdev + * @param type the type of the evdev + * @param user_data a custom parameter + */ +typedef void (*lv_evdev_discovery_cb_t)(lv_indev_t * indev, lv_evdev_type_t type, void * user_data); + /********************** * GLOBAL PROTOTYPES **********************/ @@ -30,6 +47,23 @@ extern "C" { */ lv_indev_t * lv_evdev_create(lv_indev_type_t indev_type, const char * dev_path); +/** + * Begin automatically creating evdev indevs for all new and existing + * evdev devices found in /dev/input/ + * @param cb function to call when a new evdev indev is discovered, or `NULL` + * @param user_data parameter to pass to the callback + * @return the success or failure status. It will fail if it's + * already running or resources could not be initialized. + */ +lv_result_t lv_evdev_discovery_start(lv_evdev_discovery_cb_t cb, void * user_data); + +/** + * Stop automatically creating evdev indevs. Safe to call from the + * discovery callback. + * @return the success or failure status. It will fail if it's already running. + */ +lv_result_t lv_evdev_discovery_stop(void); + /** * Set whether coordinates of pointer device should be swapped. Defaults to * false. diff --git a/src/drivers/evdev/lv_evdev_private.h b/src/drivers/evdev/lv_evdev_private.h new file mode 100644 index 000000000..d9b3352d4 --- /dev/null +++ b/src/drivers/evdev/lv_evdev_private.h @@ -0,0 +1,45 @@ +/** + * @file lv_evdev_private.h + * + */ + +#ifndef LV_EVDEV_PRIVATE_H +#define LV_EVDEV_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "lv_evdev.h" + +#if LV_USE_EVDEV + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_evdev_deinit(void); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_EVDEV*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_EVDEV_PRIVATE_H*/ diff --git a/src/drivers/sdl/lv_sdl_keyboard.c b/src/drivers/sdl/lv_sdl_keyboard.c index 0bb94d6e3..25c5d801e 100644 --- a/src/drivers/sdl/lv_sdl_keyboard.c +++ b/src/drivers/sdl/lv_sdl_keyboard.c @@ -118,7 +118,7 @@ void lv_sdl_keyboard_handler(SDL_Event * event) /*Find a suitable indev*/ lv_indev_t * indev = lv_indev_get_next(NULL); while(indev) { - if(lv_indev_get_type(indev) == LV_INDEV_TYPE_KEYPAD) { + if(lv_indev_get_read_cb(indev) == sdl_keyboard_read) { /*If disp is NULL for any reason use the first indev with the correct type*/ if(disp == NULL || lv_indev_get_display(indev) == disp) break; } diff --git a/src/drivers/sdl/lv_sdl_mouse.c b/src/drivers/sdl/lv_sdl_mouse.c index 8eff9401b..e9e1b0387 100644 --- a/src/drivers/sdl/lv_sdl_mouse.c +++ b/src/drivers/sdl/lv_sdl_mouse.c @@ -132,7 +132,7 @@ void lv_sdl_mouse_handler(SDL_Event * event) /*Find a suitable indev*/ lv_indev_t * indev = lv_indev_get_next(NULL); while(indev) { - if(lv_indev_get_type(indev) == LV_INDEV_TYPE_POINTER) { + if(lv_indev_get_read_cb(indev) == sdl_mouse_read) { /*If disp is NULL for any reason use the first indev with the correct type*/ if(disp == NULL || lv_indev_get_display(indev) == disp) break; } diff --git a/src/drivers/sdl/lv_sdl_mousewheel.c b/src/drivers/sdl/lv_sdl_mousewheel.c index b31a72309..f0b5f7d96 100644 --- a/src/drivers/sdl/lv_sdl_mousewheel.c +++ b/src/drivers/sdl/lv_sdl_mousewheel.c @@ -103,7 +103,7 @@ void lv_sdl_mousewheel_handler(SDL_Event * event) /*Find a suitable indev*/ lv_indev_t * indev = lv_indev_get_next(NULL); while(indev) { - if(lv_indev_get_type(indev) == LV_INDEV_TYPE_ENCODER) { + if(lv_indev_get_read_cb(indev) == sdl_mousewheel_read) { /*If disp is NULL for any reason use the first indev with the correct type*/ if(disp == NULL || lv_indev_get_display(indev) == disp) break; } diff --git a/src/lv_init.c b/src/lv_init.c index 18a2e0857..a266e9120 100644 --- a/src/lv_init.c +++ b/src/lv_init.c @@ -73,6 +73,9 @@ #if LV_USE_UEFI #include "drivers/uefi/lv_uefi_context.h" #endif +#if LV_USE_EVDEV + #include "drivers/evdev/lv_evdev_private.h" +#endif /********************* * DEFINES @@ -398,6 +401,10 @@ void lv_deinit(void) lv_cleanup_devices(LV_GLOBAL_DEFAULT()); +#if LV_USE_EVDEV + lv_evdev_deinit(); +#endif + #if LV_USE_SPAN != 0 lv_span_stack_deinit(); #endif diff --git a/src/misc/lv_types.h b/src/misc/lv_types.h index 7250282ac..da804d5a7 100644 --- a/src/misc/lv_types.h +++ b/src/misc/lv_types.h @@ -353,6 +353,10 @@ typedef struct _lv_xml_component_ctx_t lv_xml_component_ctx_t; typedef struct _lv_xml_parser_state_t lv_xml_parser_state_t; +#if LV_USE_EVDEV +typedef struct _lv_evdev_discovery_t lv_evdev_discovery_t; +#endif + #endif /*__ASSEMBLY__*/ /**********************