LVGL 编码器处理函数(源码注释)

本文详细描述了LV_INDEV.c中编码器输入设备的处理过程,包括按键状态的跟踪、事件触发(如按下、释放、长按)以及在编辑和导航模式下的步进操作。
摘要由CSDN通过智能技术生成

要使用 编码器或者按键类  输入设备,除了需要了解 输入设备的接口文件的架构和设计思路外,

还应该熟悉 输入设备 的信号处理过程:
下面是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;
                }
            }
        }
    }
}

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值