lvgl修改输入设备驱动使其支持鼠标右键、双击、滑轮...
我在前几章移植 lvgl 到linux上时讲过注册鼠标驱动部分,那时候使用的时默认提供的驱动,支持的鼠标功能很少,只有左键点击,那时候我提过我们可以修改驱动使其支持,下面是具体的实现。
看上面代码,我们当时是直接用的默认的模板驱动,而下面则是我专门针对鼠标写的一个驱动。这里的 evdev_fd 是输入设备的文件描述符,也就是说lvgl默认提供一种设备,所以大家如果有多个输入设备的话需要再准备几个独立的文件描述符以及驱动。这里官方提供的默认驱动是支持多种输入设备的(比如鼠标,键盘,触摸屏),所以看这代码比较多。而我们在这里专门针对鼠标进行开发驱动,使其支持我们要的效果。
首先我们打开 lv_hal_indev.h 这个文件,我们需要加上一些额外的定义,如图:
然后我们再打开lv_api_map.h,如下图添加,遵循 lvgl 的风格
然后我们再 evdev.c 文件中添加鼠标驱动函数,位置大家可自行添加,我这里添加到 evdev_read 的下边,代码部分如下,不是很难,重点是理解输入设备的一些参数意义,这里使用的 struct input_event 这个结构体,大部分鼠标都支持,如果你的鼠标是自定义的格式,那么需要自行看手册进行转化。
void mouse_event_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{struct input_event in;while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) {/* 发生鼠标移动,记录其位置 */if(in.type == EV_REL) {if(in.code == REL_X) evdev_root_x += in.value;else if(in.code == REL_Y) evdev_root_y += in.value;else if(in.code == REL_WHEEL) data->enc_diff = in.value; /* 将鼠标滑轮滚动转化为LVGL的编码器事件 */}/* 按键事件(包括鼠标) */else if(in.type == EV_KEY) {switch(in.code) {/* 左键 */case BTN_LEFT:if(in.value == 0)evdev_button = LV_INDEV_STATE_REL;else if(in.value == 1)evdev_button = LV_INDEV_STATE_PR;break;/* 右键 */case BTN_RIGHT:if(in.value == 0)evdev_button = LV_INDEV_STATE_RIGHT_REL;else if(in.value == 1)evdev_button = LV_INDEV_STATE_RIGHT_PR;break;/* 中键 */case BTN_MIDDLE:if(in.value == 0)evdev_button = LV_INDEV_STATE_MIDDLE_REL;else if(in.value == 1)evdev_button = LV_INDEV_STATE_MIDDLE_PR;break;default:break;}}/* 保存值 */data->point.x = evdev_root_x;data->point.y = evdev_root_y;data->state = evdev_button;/* 边界检测 */if(data->point.x < 0) data->point.x = 0;if(data->point.y < 0) data->point.y = 0;if(data->point.x > drv->disp->driver->hor_res) data->point.x = drv->disp->driver->hor_res;if(data->point.y > drv->disp->driver->ver_res) data->point.y = drv->disp->driver->ver_res;}
}
下面我们在修改一下sdl模拟器的驱动,我们再模拟器上进行测试,下面红框是修改部分
接下来我们看一下 lv_indev.c 输入设备核心代码,下面的这个函数是输入设备的核心函数,是 30ms 的定时函数,这个定时时间由 LV_INDEV_DEF_READ_PERIOD 这个宏决定的。而红框部分则是对输入设备的数据结构体的初始化值,最后调用我们上面写的驱动函数将读取的鼠标值转化为 lvgl 数据结构体。
而在往下看则是对不同输入设备的具体处理,我们重点关注红框部分的鼠标处理函数
这个就是处理鼠标的处理函数,先是对坐标进行了处理,由于我们判断过了这里就不再重复判断了,而最下面的判断是用于鼠标发生了移动重新绘制鼠标的位置的作用。
再往下面部分就是对事件的判断从而返给对象,红框部分是新增的使其支持我们自定义的功能。这里需要强调一下,indev_proc_press 这个函数是初次按下执行一系列操作,比如LV_EVENT_PRESSED (第一下按下时调用)、 LV_EVENT_PRESSING (还在按)、LV_EVENT_PRESS_LOST (目标丢失)、LV_EVENT_LONG_PRESSED(长按)、LV_EVENT_LONG_PRESSED_REPEAT(仍长按)这些重要的中间过,对于右键来说是大部分是不需要的,但是我们要保持完整性且目标丢失我们也需要,所以右键也去调用了这个函数
对 indev_proc_press 这个处理按下(一种过程,并非结束)的函数进行处理,重点展示修改的代码,下面“时间”打错字了,是事件
然后就是 indev_proc_release 这个函数,主要是 LV_EVENT_RELEASED(释放)、LV_EVENT_SHORT_CLICKED(短按)、LV_EVENT_CLICKED(点击)这些事件,这里右键是不需要的,所以加个判断,同时要加上右键事件以及双击事件的发送,这里改动比较多,大家需注意:
到这里成功实现了双击、右键、以及鼠标滑轮功能,我们创建个box简单测试一下
static void event_cb(lv_event_t *e)
{lv_event_code_t code = lv_event_get_code(e);if(code == LV_EVENT_CLICKED) printf("左键点击事件\n");else if(code == LV_EVENT_RIGHT_CLICKED) printf("右键点击事件\n");else if(code == LV_EVENT_DOUBLE_CLICKED) printf("左键双击事件\n");else if(code == LV_EVENT_MOUSE_WHEEL_UP) printf("鼠标滑轮上滑事件\n");else if(code == LV_EVENT_MOUSE_WHEEL_DOWN) printf("鼠标滑轮下滑事件\n");
}void page_create(void)
{lv_obj_t* box = lv_obj_create(lv_scr_act());lv_obj_set_size(box, 60, 60);lv_obj_add_event_cb(box, event_cb, LV_EVENT_ALL, NULL);
}
下面是输出打印
到这里就完结了,其实 lvgl 的知识听庞大的,需要大家慢慢挖索,我不建议大家一股脑的看源代码,而是有需求用到了再去查看,探索是枯燥的,但是忍受下来你会发现其实就是那么简单,我这里只是以三种事件为例子,其实还有鼠标悬停提示这种事件,其实也不难,需要大家好好摸索,最后谢谢大家的观看。