How to get a pressed key properly (evdev)

Description

What MCU/Processor/Board and compiler are you using?

Device with Linux kernel, using gcc10 for compilation

What LVGL version are you using?

v7.8.1 (latest master)

What do you want to achieve?

I’d like to understand how to fix a bug in my program. Currently, if I press any key other than KEY_ENTER or KEY_UP, it is not translated to my event handler as an event, despite evdev driver from lv_drivers translating the keys properly.

What have you tried so far?

  • Adding debug output to evdev LVGL driver to check if keys are translated.
  • Trying two solutions to get a pressed key (check code section)

Code to reproduce

This code is a shortened version of the actual code. Note that:

  • it won’t work in simulator
  • original code works in simulator, but doesn’t work with evdev

The full code is stored at https://github.com/HenriDellal/mobile-recovery-lvgl

#include "lv_drv_conf.h"
#include "device_config.h"
#include "lvgl/lvgl.h"

#include "lv_drivers/display/fbdev.h"

#include "lv_drivers/indev/evdev.h"

#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <threads.h>
#include <unistd.h>

static lv_indev_drv_t kp_drv;
static lv_indev_t * kp_indev;

static lv_obj_t * options;

static void mm_event_handler(lv_obj_t * obj, lv_event_t ev) {
    uint32_t key = lv_indev_get_key(kp_indev);
    // other non-working solution is
    // uint32_t * key = (uint32_t *) lv_event_get_data();
    printf("mm_event: %d\n", key);
}

static void open_menu(lv_event_cb_t ev_handler) {
    lv_list_clean(options);
    lv_obj_t * list_btn;

    list_btn = lv_list_add_btn(options, NULL, "First");
    lv_obj_set_event_cb(list_btn, ev_handler);
    lv_list_focus_btn(options, list_btn);

    list_btn = lv_list_add_btn(options, NULL, "Second");
    lv_obj_set_event_cb(list_btn, ev_handler);

    list_btn = lv_list_add_btn(options, NULL, "Third");
    lv_obj_set_event_cb(list_btn, ev_handler);
}

void tick_thrd() {
    for(;;) {
        usleep(5); // Sleep for 5 milliseconds
        lv_tick_inc(5); // Tell LVGL that 5 milliseconds have passed
        lv_task_handler(); // Tell LVGL to do its stuff
    }
}

int main() {
    thrd_t tick_thrd_t;
    lv_init();
    fbdev_init();
    evdev_init();

    // Set up buffer
    static lv_disp_buf_t disp_buf;
    static lv_color_t buf[LV_HOR_RES_MAX * LV_VER_RES_MAX];
    lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX);

    // Set up display
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.buffer = &disp_buf;
    disp_drv.flush_cb = fbdev_flush;
    lv_disp_drv_register(&disp_drv);

    // Setup keyboard driver
    lv_indev_drv_init(&kp_drv);
    kp_drv.type = LV_INDEV_TYPE_KEYPAD;
    kp_drv.read_cb = evdev_read;
    kp_indev = lv_indev_drv_register(&kp_drv);

    lv_group_t * group = lv_group_create();
    lv_indev_set_group(kp_indev, group);

    // Create "ticking" thread
    thrd_create(&tick_thrd_t, (thrd_start_t)tick_thrd, NULL);

    options = lv_list_create(lv_scr_act(), NULL);
    lv_group_add_obj(group, options);
    open_menu(mm_event_handler);
    lv_obj_set_event_cb(options, mm_event_handler);

    // Sleep forever
    for(;;)
        usleep(5000);
}

The lv_event_get_data solution should work, but you have to use it only when LV_EVENT_KEY is sent.

You may also need to register the event handler on the list object, not the individual buttons.

Thanks.

The problem is whatever solution I try, the handler doesn’t get called when other keys are pressed, no matter what type of event is.

I forgot to mention that I did, this is the shortened version and I must have skipped this call. I’m editing the post now.

In that case, I’d suggest setting a breakpoint in the evdev driver when you press one of the broken keys, then stepping through the LVGL input code till you find where it’s rejecting the keys. I am not sure why it would work for ENTER and UP but not others.