Screen Manager

管理多个界面(Screen)的创建、切换与输入事件分发。LVGL 中推荐基于 lv_group_t 的原生事件机制(方式一),仅在资源极度受限且交互极简的场景下才考虑手动路由(方式二)。

方式一

利用 lv_group_t 接收输入事件,通过 lv_indev_set_group() 切换焦点,由 LVGL 事件循环自动派发 LV_EVENT_KEY。

lv_obj_add_event_cb(screen, key_cb, LV_EVENT_KEY, NULL);
lv_group_add_obj(group, screen);

detail.c

static lv_obj_t *screen;
static lv_group_t *group;
// 对完提供获取group
lv_group_t * detail_get_group(void)
{
    return group;
}
// 接收 LV_EVENT_KEY 的回调,在这里根据输入的按键处理业务需求
static void key_cb(lv_event_t *e)
{
    uint32_t key = lv_event_get_key(e);
    printf("key=%d\n", key);
}
// 创建界面
lv_obj_t * create_detail(void)
{
    screen = lv_obj_create(NULL);
    group = lv_group_create();
	//这里重要,screen
    lv_obj_add_event_cb(screen, key_cb, LV_EVENT_KEY, NULL);
    lv_group_add_obj(group, screen);
    return scr;
}

screen_manager.c

// 界面枚举,每个界面对应一个枚举
typedef enum {
    SCREEN_MASTER,
    SCREEN_SETTINGS,
    SCREEN_DETAIL,
    SCREEN_COUNT,
} screen_id_t;
// 界面结构体,
typedef struct {
    lv_obj_t *screen; // 界面screen本身
    lv_group_t *group;// group组
} screen_entry_t;
// 保存界面的数组
static screen_entry_t screens[SCREEN_COUNT];

// 初始化创建所有界面
void screen_mgr_init(void)
{
    screens[SCREEN_MASTER]  = (screen_entry_t){ create_master(),   master_get_group() };
    screens[SCREEN_SETTINGS]= (screen_entry_t){ create_settings(), settings_get_group() };
    screens[SCREEN_DETAIL]  = (screen_entry_t){ create_detail(),   detail_get_group() };
}
// 界面切换
void screen_mgr_switch(screen_id_t id) //传入screen_id_t枚举
{
    lv_scr_load(screens[id].scr);//切换时,加载一个界面
    lv_indev_set_group(indev_get(), screens[id].grp);//切换界面后,设置输入事件的焦点到这个界面的group
}

方式二

判断当前所在的界面,输入事件触发时调用这个界面的回调key_cb

detail.c

static lv_obj_t *scr;
// 只需要提供回调函数就好
void detail_key_cb(uint32_t key)
{
    printf("detail->key=%d\n", key);
    //处理
}

lv_obj_t * create_detail(void)
{
    scr = lv_obj_create(NULL);
	// 不需要任何操作
    return scr;
}

screen_manager.c

typedef enum {
    SCREEN_MASTER,
    SCREEN_SETTINGS,
    SCREEN_DETAIL,
    SCREEN_COUNT,
} screen_id_t;
static lv_obj_t *screens[SCREEN_COUNT];
static screen_id_t now_screen; //当前界面

void screen_mgr_init(void)
{
    screens[SCREEN_MASTER]  = create_master();
    screens[SCREEN_SETTINGS]= create_settings();
    screens[SCREEN_DETAIL]  = create_detail();
}

void screen_mgr_switch(screen_id_t id)
{
    lv_scr_load(screens[id]);//切换时,加载一个界面
    now_screen = id;
}
//获取当前界面
screen_id_t get_now_screen(void)
{
    return now_screen;
}
//界面路由处理
typedef void (*key_handler_t)(uint32_t);

static const key_handler_t key_handlers[SCREEN_COUNT] = {
    [SCREEN_MASTER]   = master_key_cb,
    [SCREEN_SETTINGS] = settings_key_cb,
    [SCREEN_DETAIL]   = detail_key_cb,
};

void screen_mgr_dispatch_key(uint32_t key)
{
    if (now_screen < SCREEN_COUNT && key_handlers[now_screen]) {
        key_handlers[now_screen](key);
    }
}

evdev.c

void evdev_read(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
    data->key = last_key;
    data->state = last_state;
    
    struct input_event ev;
    if (read(evdev_fd, &ev, sizeof(ev)) != sizeof(ev))
        return;

    last_key = k;
    last_state = ev.value == 1 ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;

    if (ev.value == 1) {                        // ← 只处理按下
        screen_mgr_dispatch_key(k);
    }
}