mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
feat(drivers): add evdev discovery (#7481)
This commit is contained in:
parent
b9dd8b1172
commit
4744bbe194
@ -55,3 +55,48 @@ You can use ``evtest`` to show data from that event source to see if it is actua
|
|||||||
Try:
|
Try:
|
||||||
|
|
||||||
``$evtest /dev/input/event1`` replacing ``eventX`` with your event device from above.
|
``$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.
|
||||||
|
@ -47,6 +47,7 @@ extern "C" {
|
|||||||
#include "src/draw/sw/blend/lv_draw_sw_blend_private.h"
|
#include "src/draw/sw/blend/lv_draw_sw_blend_private.h"
|
||||||
#include "src/drivers/libinput/lv_xkb_private.h"
|
#include "src/drivers/libinput/lv_xkb_private.h"
|
||||||
#include "src/drivers/libinput/lv_libinput_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/font/lv_font_fmt_txt_private.h"
|
||||||
#include "src/themes/lv_theme_private.h"
|
#include "src/themes/lv_theme_private.h"
|
||||||
#include "src/core/lv_refr_private.h"
|
#include "src/core/lv_refr_private.h"
|
||||||
|
@ -233,6 +233,9 @@ typedef struct _lv_global_t {
|
|||||||
bool freertos_idle_task_running;
|
bool freertos_idle_task_running;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LV_USE_EVDEV
|
||||||
|
lv_evdev_discovery_t * evdev_discovery;
|
||||||
|
#endif
|
||||||
|
|
||||||
void * user_data;
|
void * user_data;
|
||||||
} lv_global_t;
|
} lv_global_t;
|
||||||
|
@ -6,24 +6,42 @@
|
|||||||
/**********************
|
/**********************
|
||||||
* INCLUDES
|
* INCLUDES
|
||||||
**********************/
|
**********************/
|
||||||
#include "lv_evdev.h"
|
#include "lv_evdev_private.h"
|
||||||
#if LV_USE_EVDEV
|
#if LV_USE_EVDEV
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/param.h> /*To detect BSD*/
|
#include <sys/param.h> /*To detect BSD*/
|
||||||
#ifdef BSD
|
#ifdef BSD
|
||||||
#include <dev/evdev/input.h>
|
#include <dev/evdev/input.h>
|
||||||
#else
|
#else
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
#include <sys/inotify.h>
|
||||||
#endif /*BSD*/
|
#endif /*BSD*/
|
||||||
|
#include "../../core/lv_global.h"
|
||||||
|
#include "../../misc/lv_types.h"
|
||||||
#include "../../misc/lv_assert.h"
|
#include "../../misc/lv_assert.h"
|
||||||
#include "../../misc/lv_math.h"
|
#include "../../misc/lv_math.h"
|
||||||
|
#include "../../misc/lv_async.h"
|
||||||
#include "../../stdlib/lv_mem.h"
|
#include "../../stdlib/lv_mem.h"
|
||||||
#include "../../stdlib/lv_string.h"
|
#include "../../stdlib/lv_string.h"
|
||||||
#include "../../display/lv_display.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
|
* TYPEDEFS
|
||||||
@ -32,6 +50,9 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
/*Device*/
|
/*Device*/
|
||||||
int fd;
|
int fd;
|
||||||
|
dev_t st_dev;
|
||||||
|
ino_t st_ino;
|
||||||
|
lv_evdev_type_t type;
|
||||||
/*Config*/
|
/*Config*/
|
||||||
bool swap_axes;
|
bool swap_axes;
|
||||||
int min_x;
|
int min_x;
|
||||||
@ -43,8 +64,19 @@ typedef struct {
|
|||||||
int root_y;
|
int root_y;
|
||||||
int key;
|
int key;
|
||||||
lv_indev_state_t state;
|
lv_indev_state_t state;
|
||||||
|
bool deleting;
|
||||||
} lv_evdev_t;
|
} 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
|
* STATIC FUNCTIONS
|
||||||
**********************/
|
**********************/
|
||||||
@ -108,6 +140,12 @@ static lv_point_t _evdev_process_pointer(lv_indev_t * indev, int x, int y)
|
|||||||
return p;
|
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)
|
static void _evdev_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||||
{
|
{
|
||||||
lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
|
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*/
|
/*Update dsc with buffered events*/
|
||||||
struct input_event in = { 0 };
|
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.type == EV_REL) {
|
||||||
if(in.code == REL_X) dsc->root_x += in.value;
|
if(in.code == REL_X) dsc->root_x += in.value;
|
||||||
else if(in.code == REL_Y) dsc->root_y += 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*/
|
/*Process and store in data*/
|
||||||
switch(lv_indev_get_type(indev)) {
|
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
|
* 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);
|
dsc->fd = open(dev_path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
|
||||||
if(dsc->fd < 0) {
|
if(dsc->fd < 0) {
|
||||||
LV_LOG_ERROR("open failed: %s", strerror(errno));
|
LV_LOG_WARN("open failed: %s", strerror(errno));
|
||||||
goto err_after_malloc;
|
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) {
|
if(fcntl(dsc->fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||||
LV_LOG_ERROR("fcntl failed: %s", strerror(errno));
|
LV_LOG_ERROR("fcntl failed: %s", strerror(errno));
|
||||||
goto err_after_open;
|
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;
|
dsc->max_x = absinfo.maximum;
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
if(ioctl(dsc->fd, EVIOCGABS(ABS_Y), &absinfo) == 0) {
|
||||||
dsc->min_y = absinfo.minimum;
|
dsc->min_y = absinfo.minimum;
|
||||||
dsc->max_y = absinfo.maximum;
|
dsc->max_y = absinfo.maximum;
|
||||||
}
|
}
|
||||||
else {
|
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_type(indev, indev_type);
|
||||||
lv_indev_set_read_cb(indev, _evdev_read);
|
lv_indev_set_read_cb(indev, _evdev_read);
|
||||||
lv_indev_set_driver_data(indev, dsc);
|
lv_indev_set_driver_data(indev, dsc);
|
||||||
|
lv_indev_add_event_cb(indev, _evdev_indev_delete_cb, LV_EVENT_DELETE, NULL);
|
||||||
|
|
||||||
return indev;
|
return indev;
|
||||||
|
|
||||||
err_after_open:
|
err_after_open:
|
||||||
@ -214,6 +447,66 @@ err_after_malloc:
|
|||||||
return NULL;
|
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)
|
void lv_evdev_set_swap_axes(lv_indev_t * indev, bool swap_axes)
|
||||||
{
|
{
|
||||||
lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
|
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)
|
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);
|
lv_indev_delete(indev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lv_evdev_deinit(void)
|
||||||
|
{
|
||||||
|
lv_evdev_discovery_stop();
|
||||||
|
}
|
||||||
|
|
||||||
#endif /*LV_USE_EVDEV*/
|
#endif /*LV_USE_EVDEV*/
|
||||||
|
@ -18,6 +18,23 @@ extern "C" {
|
|||||||
|
|
||||||
#if LV_USE_EVDEV
|
#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
|
* GLOBAL PROTOTYPES
|
||||||
**********************/
|
**********************/
|
||||||
@ -30,6 +47,23 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
lv_indev_t * lv_evdev_create(lv_indev_type_t indev_type, const char * dev_path);
|
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
|
* Set whether coordinates of pointer device should be swapped. Defaults to
|
||||||
* false.
|
* false.
|
||||||
|
45
src/drivers/evdev/lv_evdev_private.h
Normal file
45
src/drivers/evdev/lv_evdev_private.h
Normal file
@ -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*/
|
@ -118,7 +118,7 @@ void lv_sdl_keyboard_handler(SDL_Event * event)
|
|||||||
/*Find a suitable indev*/
|
/*Find a suitable indev*/
|
||||||
lv_indev_t * indev = lv_indev_get_next(NULL);
|
lv_indev_t * indev = lv_indev_get_next(NULL);
|
||||||
while(indev) {
|
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 is NULL for any reason use the first indev with the correct type*/
|
||||||
if(disp == NULL || lv_indev_get_display(indev) == disp) break;
|
if(disp == NULL || lv_indev_get_display(indev) == disp) break;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ void lv_sdl_mouse_handler(SDL_Event * event)
|
|||||||
/*Find a suitable indev*/
|
/*Find a suitable indev*/
|
||||||
lv_indev_t * indev = lv_indev_get_next(NULL);
|
lv_indev_t * indev = lv_indev_get_next(NULL);
|
||||||
while(indev) {
|
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 is NULL for any reason use the first indev with the correct type*/
|
||||||
if(disp == NULL || lv_indev_get_display(indev) == disp) break;
|
if(disp == NULL || lv_indev_get_display(indev) == disp) break;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ void lv_sdl_mousewheel_handler(SDL_Event * event)
|
|||||||
/*Find a suitable indev*/
|
/*Find a suitable indev*/
|
||||||
lv_indev_t * indev = lv_indev_get_next(NULL);
|
lv_indev_t * indev = lv_indev_get_next(NULL);
|
||||||
while(indev) {
|
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 is NULL for any reason use the first indev with the correct type*/
|
||||||
if(disp == NULL || lv_indev_get_display(indev) == disp) break;
|
if(disp == NULL || lv_indev_get_display(indev) == disp) break;
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,9 @@
|
|||||||
#if LV_USE_UEFI
|
#if LV_USE_UEFI
|
||||||
#include "drivers/uefi/lv_uefi_context.h"
|
#include "drivers/uefi/lv_uefi_context.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if LV_USE_EVDEV
|
||||||
|
#include "drivers/evdev/lv_evdev_private.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/*********************
|
/*********************
|
||||||
* DEFINES
|
* DEFINES
|
||||||
@ -398,6 +401,10 @@ void lv_deinit(void)
|
|||||||
|
|
||||||
lv_cleanup_devices(LV_GLOBAL_DEFAULT());
|
lv_cleanup_devices(LV_GLOBAL_DEFAULT());
|
||||||
|
|
||||||
|
#if LV_USE_EVDEV
|
||||||
|
lv_evdev_deinit();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LV_USE_SPAN != 0
|
#if LV_USE_SPAN != 0
|
||||||
lv_span_stack_deinit();
|
lv_span_stack_deinit();
|
||||||
#endif
|
#endif
|
||||||
|
@ -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;
|
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__*/
|
#endif /*__ASSEMBLY__*/
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
|
Loading…
x
Reference in New Issue
Block a user