feat(dev): port evdev input driver (#4672)
This commit is contained in:
4
Kconfig
4
Kconfig
@@ -1319,6 +1319,10 @@ menu "LVGL configuration"
|
||||
config LV_USE_TFT_ESPI
|
||||
bool "Use TFT_eSPI driver"
|
||||
default n
|
||||
|
||||
config LV_USE_EVDEV
|
||||
bool "Use evdev input driver"
|
||||
default n
|
||||
endmenu
|
||||
|
||||
menu "Examples"
|
||||
|
||||
@@ -782,6 +782,9 @@
|
||||
/*Interface for TFT_eSPI*/
|
||||
#define LV_USE_TFT_ESPI 0
|
||||
|
||||
/*Driver for evdev input devices*/
|
||||
#define LV_USE_EVDEV 0
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
*==================*/
|
||||
|
||||
2
lvgl.h
2
lvgl.h
@@ -123,6 +123,8 @@ extern "C" {
|
||||
#include "src/dev/nuttx/lv_nuttx_touchscreen.h"
|
||||
#include "src/dev/nuttx/lv_nuttx_lcd.h"
|
||||
|
||||
#include "src/dev/evdev/lv_evdev.h"
|
||||
|
||||
#include "src/core/lv_global.h"
|
||||
/*********************
|
||||
* DEFINES
|
||||
|
||||
224
src/dev/evdev/lv_evdev.c
Normal file
224
src/dev/evdev/lv_evdev.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @file lv_evdev.c
|
||||
*
|
||||
*/
|
||||
|
||||
/**********************
|
||||
* INCLUDES
|
||||
**********************/
|
||||
#include "lv_evdev.h"
|
||||
#if LV_USE_EVDEV
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/param.h> /*To detect BSD*/
|
||||
#ifdef BSD
|
||||
#include <dev/evdev/input.h>
|
||||
#else
|
||||
#include <linux/input.h>
|
||||
#endif /*BSD*/
|
||||
#include "../../misc/lv_assert.h"
|
||||
#include "../../misc/lv_math.h"
|
||||
#include "../../stdlib/lv_mem.h"
|
||||
#include "../../stdlib/lv_string.h"
|
||||
#include "../../display/lv_display.h"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
/*Device*/
|
||||
int fd;
|
||||
/*Config*/
|
||||
bool swap_axes;
|
||||
int min_x;
|
||||
int min_y;
|
||||
int max_x;
|
||||
int max_y;
|
||||
/*State*/
|
||||
int root_x;
|
||||
int root_y;
|
||||
int key;
|
||||
lv_indev_state_t state;
|
||||
} lv_evdev_t;
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static int _evdev_process_key(uint16_t code)
|
||||
{
|
||||
switch(code) {
|
||||
case KEY_UP:
|
||||
return LV_KEY_UP;
|
||||
case KEY_DOWN:
|
||||
return LV_KEY_DOWN;
|
||||
case KEY_RIGHT:
|
||||
return LV_KEY_RIGHT;
|
||||
case KEY_LEFT:
|
||||
return LV_KEY_LEFT;
|
||||
case KEY_ESC:
|
||||
return LV_KEY_ESC;
|
||||
case KEY_DELETE:
|
||||
return LV_KEY_DEL;
|
||||
case KEY_BACKSPACE:
|
||||
return LV_KEY_BACKSPACE;
|
||||
case KEY_ENTER:
|
||||
return LV_KEY_ENTER;
|
||||
case KEY_NEXT:
|
||||
case KEY_TAB:
|
||||
return LV_KEY_NEXT;
|
||||
case KEY_PREVIOUS:
|
||||
return LV_KEY_PREV;
|
||||
case KEY_HOME:
|
||||
return LV_KEY_HOME;
|
||||
case KEY_END:
|
||||
return LV_KEY_END;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int _evdev_calibrate(int v, int in_min, int in_max, int out_min, int out_max)
|
||||
{
|
||||
if(in_min != in_max) v = (v - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
return LV_CLAMP(out_min, v, out_max);
|
||||
}
|
||||
|
||||
static lv_point_t _evdev_process_pointer(lv_indev_t * indev, int x, int y)
|
||||
{
|
||||
lv_display_t * disp = lv_indev_get_disp(indev);
|
||||
lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
|
||||
LV_ASSERT_NULL(dsc);
|
||||
|
||||
int swapped_x = dsc->swap_axes ? y : x;
|
||||
int swapped_y = dsc->swap_axes ? x : y;
|
||||
|
||||
int offset_x = lv_display_get_offset_x(disp);
|
||||
int offset_y = lv_display_get_offset_y(disp);
|
||||
int width = lv_display_get_horizontal_resolution(disp);
|
||||
int height = lv_display_get_vertical_resolution(disp);
|
||||
|
||||
lv_point_t p;
|
||||
p.x = _evdev_calibrate(swapped_x, dsc->min_x, dsc->max_x, offset_x, offset_x + width - 1);
|
||||
p.y = _evdev_calibrate(swapped_y, dsc->min_y, dsc->max_y, offset_y, offset_y + height - 1);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void _evdev_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
|
||||
LV_ASSERT_NULL(dsc);
|
||||
|
||||
/*Update dsc with buffered events*/
|
||||
struct input_event in = { 0 };
|
||||
while(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;
|
||||
}
|
||||
else if(in.type == EV_ABS) {
|
||||
if(in.code == ABS_X || in.code == ABS_MT_POSITION_X) dsc->root_x = in.value;
|
||||
else if(in.code == ABS_Y || in.code == ABS_MT_POSITION_Y) dsc->root_y = in.value;
|
||||
else if(in.code == ABS_MT_TRACKING_ID) {
|
||||
if(in.value == -1) dsc->state = LV_INDEV_STATE_RELEASED;
|
||||
else if(in.value == 0) dsc->state = LV_INDEV_STATE_PRESSED;
|
||||
}
|
||||
}
|
||||
else if(in.type == EV_KEY) {
|
||||
if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) {
|
||||
if(in.value == 0) dsc->state = LV_INDEV_STATE_RELEASED;
|
||||
else if(in.value == 1) dsc->state = LV_INDEV_STATE_PRESSED;
|
||||
}
|
||||
else {
|
||||
dsc->key = _evdev_process_key(in.code);
|
||||
if(dsc->key) {
|
||||
dsc->state = in.value ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
|
||||
data->continue_reading = true; /*Keep following events in buffer for now*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*Process and store in data*/
|
||||
switch(lv_indev_get_type(indev)) {
|
||||
case LV_INDEV_TYPE_KEYPAD:
|
||||
data->state = dsc->state;
|
||||
data->key = dsc->key;
|
||||
break;
|
||||
case LV_INDEV_TYPE_POINTER:
|
||||
data->state = dsc->state;
|
||||
data->point = _evdev_process_pointer(indev, dsc->root_x, dsc->root_y);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_indev_t * lv_evdev_create(lv_indev_type_t indev_type, const char * dev_path)
|
||||
{
|
||||
lv_evdev_t * dsc = lv_malloc(sizeof(lv_evdev_t));
|
||||
LV_ASSERT_MALLOC(dsc);
|
||||
if(dsc == NULL) return NULL;
|
||||
lv_memzero(dsc, sizeof(lv_evdev_t));
|
||||
|
||||
dsc->fd = open(dev_path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
|
||||
if(dsc->fd < 0) {
|
||||
LV_LOG_ERROR("open failed: %s", strerror(errno));
|
||||
goto err_after_malloc;
|
||||
}
|
||||
|
||||
if(fcntl(dsc->fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
LV_LOG_ERROR("fcntl failed: %s", strerror(errno));
|
||||
goto err_after_open;
|
||||
}
|
||||
|
||||
lv_indev_t * indev = lv_indev_create();
|
||||
if(indev == NULL) goto err_after_open;
|
||||
lv_indev_set_type(indev, indev_type);
|
||||
lv_indev_set_read_cb(indev, _evdev_read);
|
||||
lv_indev_set_driver_data(indev, dsc);
|
||||
return indev;
|
||||
|
||||
err_after_open:
|
||||
close(dsc->fd);
|
||||
err_after_malloc:
|
||||
lv_free(dsc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void lv_evdev_set_swap_axes(lv_indev_t * indev, bool swap_axes)
|
||||
{
|
||||
lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
|
||||
LV_ASSERT_NULL(dsc);
|
||||
dsc->swap_axes = swap_axes;
|
||||
}
|
||||
|
||||
void lv_evdev_set_calibration(lv_indev_t * indev, int min_x, int min_y, int max_x, int max_y)
|
||||
{
|
||||
lv_evdev_t * dsc = lv_indev_get_driver_data(indev);
|
||||
LV_ASSERT_NULL(dsc);
|
||||
dsc->min_x = min_x;
|
||||
dsc->min_y = min_y;
|
||||
dsc->max_x = max_x;
|
||||
dsc->max_y = max_y;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_EVDEV*/
|
||||
64
src/dev/evdev/lv_evdev.h
Normal file
64
src/dev/evdev/lv_evdev.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @file lv_evdev.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_EVDEV_H
|
||||
#define LV_EVDEV_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../indev/lv_indev.h"
|
||||
|
||||
#if LV_USE_EVDEV
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Create evdev input device.
|
||||
* @param type LV_INDEV_TYPE_POINTER or LV_INDEV_TYPE_KEYPAD
|
||||
* @param dev_path device path, e.g., /dev/input/event0
|
||||
* @return pointer to input device or NULL if opening failed
|
||||
*/
|
||||
lv_indev_t * lv_evdev_create(lv_indev_type_t indev_type, const char * dev_path);
|
||||
|
||||
/**
|
||||
* Set whether coordinates of pointer device should be swapped. Defaults to
|
||||
* false.
|
||||
* @param indev evdev input device
|
||||
* @param swap_axes whether to swap x and y axes
|
||||
*/
|
||||
void lv_evdev_set_swap_axes(lv_indev_t * indev, bool swap_axes);
|
||||
|
||||
/**
|
||||
* Configure a coordinate transformation for pointer devices. Applied after
|
||||
* axis swap, if any. Defaults to apply no transformation.
|
||||
* @param indev evdev input device
|
||||
* @param min_x pointer coordinate mapped to min x of display
|
||||
* @param min_y pointer coordinate mapped to min y of display
|
||||
* @param max_x pointer coordinate mapped to max x of display
|
||||
* @param max_y pointer coordinate mapped to max y of display
|
||||
*/
|
||||
void lv_evdev_set_calibration(lv_indev_t * indev, int min_x, int min_y, int max_x, int max_y);
|
||||
|
||||
/**
|
||||
* Remove evdev input device.
|
||||
* @param indev evdev input device to close and free
|
||||
*/
|
||||
void lv_evdev_delete(lv_indev_t * indev);
|
||||
|
||||
#endif /*LV_USE_EVDEV*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_EVDEV_H*/
|
||||
@@ -2560,6 +2560,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Driver for evdev input devices*/
|
||||
#ifndef LV_USE_EVDEV
|
||||
#ifdef CONFIG_LV_USE_EVDEV
|
||||
#define LV_USE_EVDEV CONFIG_LV_USE_EVDEV
|
||||
#else
|
||||
#define LV_USE_EVDEV 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
*==================*/
|
||||
|
||||
Reference in New Issue
Block a user