要使用 编码器或者按键类 输入设备,除了需要了解 输入设备的接口文件的架构和设计思路外,
还应该熟悉 输入设备 的信号处理过程:
下面是lv_indev.c中 编码器的处理过程
/**
* 处理来自LV_INDEV_TYPE_ENCODER输入设备的新点
* @param i 指向输入设备的指针
* @param data 指向从输入设备读取的数据的指针
*/
static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
{
// 如果当前状态为按下且等待释放标志被设置,则直接返回,不处理
if(data->state == LV_INDEV_STATE_PRESSED && i->proc.wait_until_release) return;
// 如果设置了等待释放标志,则重置相关处理状态
if(i->proc.wait_until_release) {
i->proc.wait_until_release = 0; // 重置等待释放标志
i->proc.pr_timestamp = 0; // 重置按下时间戳
i->proc.long_pr_sent = 0; // 重置长按发送标志
i->proc.types.keypad.last_state = LV_INDEV_STATE_RELEASED; // 设置上一状态为释放,跳过释放处理
}
// 在任何其他处理之前保存最后的按键状态。如果函数因任何原因返回,它们需要已经被保存
lv_indev_state_t last_state = i->proc.types.keypad.last_state; // 保存上一个状态
i->proc.types.keypad.last_state = data->state; // 更新当前状态
i->proc.types.keypad.last_key = data->key; // 更新按键值
lv_group_t * g = i->group; // 获取输入设备关联的组
if(g == NULL) return; // 如果没有关联组,则直接返回
indev_obj_act = lv_group_get_focused(g); // 获取当前焦点对象
if(indev_obj_act == NULL) return; // 如果没有焦点对象,则直接返回
// 仅当按钮释放时才处理步进值
if(data->state != LV_INDEV_STATE_RELEASED) {
data->enc_diff = 0; // 如果状态不是释放,则步进差值置为0
}
// 刷新焦点对象。由于可能通过lv_group_focus_prev/next更改,需要重新获取
indev_obj_act = lv_group_get_focused(g);
if(indev_obj_act == NULL) return;
// 按钮按下事件处理
if(data->state == LV_INDEV_STATE_PRESSED && last_state == LV_INDEV_STATE_RELEASED) {
LV_LOG_INFO("pressed"); // 记录按下信息
i->proc.pr_timestamp = lv_tick_get(); // 记录按下时间戳
// 根据按键类型分别处理
if(data->key == LV_KEY_ENTER) {
bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
// 如果对象处于编辑模式或不可滚动,则发送按下事件
if(lv_group_get_editing(g) == true || editable_or_scrollable == false) {
lv_event_send(indev_obj_act, LV_EVENT_PRESSED, indev_act);
if(indev_reset_check(&i->proc)) return;
}
}
else if(data->key == LV_KEY_LEFT) {
// 模拟编码器左旋
data->enc_diff--;
}
else if(data->key == LV_KEY_RIGHT) {
// 模拟编码器右旋
data->enc_diff++;
}
else if(data->key == LV_KEY_ESC) {
// 将ESC作为普通按键发送
lv_group_send_data(g, LV_KEY_ESC);
if(indev_reset_check(&i->proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_CANCEL, indev_act);
if(indev_reset_check(&i->proc)) return;
}
// 将其他按键直接发送给对象(例如'A'或`LV_GROUP_KEY_RIGHT`)
else {
lv_group_send_data(g, data->key);
if(indev_reset_check(&i->proc)) return;
}
}
// 持续按压处理
else if(data->state == LV_INDEV_STATE_PRESSED && last_state == LV_INDEV_STATE_PRESSED) {
// 长按处理
if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver->long_press_time) {
i->proc.long_pr_sent = 1;
i->proc.longpr_rep_timestamp = lv_tick_get();
// 长按ENTER键的特殊处理
if(data->key == LV_KEY_ENTER) {
bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
// 在可编辑或可滚动对象上长按ENTER键切换编辑模式
if(editable_or_scrollable) {
// 如果组中只有一个对象,则不退出编辑模式(无处导航)
if(lv_group_get_obj_count(g) > 1) {
LV_LOG_INFO("toggling edit mode");
lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); // 切换编辑模式
lv_obj_clear_state(indev_obj_act, LV_STATE_PRESSED); // 手动移除按压状态
}
}
// 如果对象不可编辑,则仅发送长按事件
else {
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, indev_act);
if(indev_reset_check(&i->proc)) return;
}
}
i->proc.long_pr_sent = 1;
}
// 长按重复时间已到?
else if(i->proc.long_pr_sent != 0 && lv_tick_elaps(i->proc.longpr_rep_timestamp) > i->driver->long_press_repeat_time) {
i->proc.longpr_rep_timestamp = lv_tick_get();
// 根据按键类型进行长按重复事件的处理
if(data->key == LV_KEY_ENTER) {
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, indev_act);
if(indev_reset_check(&i->proc)) return;
}
else if(data->key == LV_KEY_LEFT) {
// 模拟编码器左旋
data->enc_diff--;
}
else if(data->key == LV_KEY_RIGHT) {
// 模拟编码器右旋
data->enc_diff++;
}
else {
// 将其他按键直接发送给对象
lv_group_send_data(g, data->key);
if(indev_reset_check(&i->proc)) return;
}
}
}
// 释放事件处理
else if(data->state == LV_INDEV_STATE_RELEASED && last_state == LV_INDEV_STATE_PRESSED) {
LV_LOG_INFO("released"); // 记录释放信息
// 释放ENTER键的特殊处理
if(data->key == LV_KEY_ENTER) {
bool editable_or_scrollable = lv_obj_is_editable(indev_obj_act) ||
lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_SCROLLABLE);
// 在非可编辑对象上释放按钮。仅发送enter
if(editable_or_scrollable == false) {
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
if(indev_reset_check(&i->proc)) return;
if(i->proc.long_pr_sent == 0) lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
if(indev_reset_check(&i->proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
if(indev_reset_check(&i->proc)) return;
}
// 正在编辑的对象上释放按钮
else if(lv_group_get_editing(g)) {
// 忽略来自模式切换的长按释放
if(!i->proc.long_pr_sent || lv_group_get_obj_count(g) <= 1) {
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, indev_act);
if(indev_reset_check(&i->proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, indev_act);
if(indev_reset_check(&i->proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, indev_act);
if(indev_reset_check(&i->proc)) return;
lv_group_send_data(g, LV_KEY_ENTER);
if(indev_reset_check(&i->proc)) return;
}
else {
lv_obj_clear_state(indev_obj_act, LV_STATE_PRESSED); // 手动移除按压状态
}
}
// 如果焦点对象可编辑且当前处于导航模式,则在ENTER释放时切换到编辑模式
else if(!i->proc.long_pr_sent) {
LV_LOG_INFO("entering edit mode");
lv_group_set_editing(g, true); // 设置编辑模式
}
}
i->proc.pr_timestamp = 0; // 重置按下时间戳
i->proc.long_pr_sent = 0; // 重置长按发送标志
}
indev_obj_act = NULL; // 重置当前活动对象指针
// 如果有编码器步进或通过左/右键模拟的步进
if(data->enc_diff != 0) {
// 在编辑模式下发送左/右键
if(lv_group_get_editing(g)) {
LV_LOG_INFO("rotated by %+d (edit)", data->enc_diff); // 记录编辑模式下的旋转信息
int32_t s;
if(data->enc_diff < 0) {
for(s = 0; s < -data->enc_diff; s++) {
lv_group_send_data(g, LV_KEY_LEFT); // 发送左键
if(indev_reset_check(&i->proc)) return;
}
}
else if(data->enc_diff > 0) {
for(s = 0; s < data->enc_diff; s++) {
lv_group_send_data(g, LV_KEY_RIGHT); // 发送右键
if(indev_reset_check(&i->proc)) return;
}
}
}
// 在导航模式下聚焦下一个/上一个对象
else {
LV_LOG_INFO("rotated by %+d (nav)", data->enc_diff); // 记录导航模式下的旋转信息
int32_t s;
if(data->enc_diff < 0) {
for(s = 0; s < -data->enc_diff; s++) {
lv_group_focus_prev(g); // 聚焦上一个对象
if(indev_reset_check(&i->proc)) return;
}
}
else if(data->enc_diff > 0) {
for(s = 0; s < data->enc_diff; s++) {
lv_group_focus_next(g); // 聚焦下一个对象
if(indev_reset_check(&i->proc)) return;
}
}
}
}
}