Cannot get Indev Keypad and Text Areas to work. What am I missing? (FIXED)

Description

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

Board: ESP32S3 DevkitC-1 v1.1
IDE: ESP-IDF v5.4.0 with VSCode extension
Compiler: CMake (esp-idf built in)
Hardware: ILI 9488 3.5 inch TFT Display and PCB matrix keypad

What LVGL version are you using?

9.2.2 (master)

What do you want to achieve?

I would like to navigate between 4 text areas, be able to input text into each of those text areas, and include a button to move to another screen all via a physical keypad. The keypad I am using has the keys 0 through 9, “.”, back, enter, and up, down, left, and right.

This is my first ever project using LVGL and the ESP-IDF ecosystem. I have spent the past 3 days trying everything I can and for the life of me cannot figure it out. I am getting nowhere as I seem to be having a fundamental misunderstanding somewhere

What have you tried so far?

  1. I have created the keypad as an indev keypad device following the documentation.
  2. I created two text areas, some labels, and a button to simplify what I’m trying to do right now.
  3. I have added everything to a group and set the indev keypad to that group.

From reading the documentation and looking at other examples, the navigation and keypad inputs should all be handled via the group now. This seems like magic and I feel as though I am missing something. Maybe adding event callbacks to each text area? Flags? If so, what do I need to add?

Currently the inputs from the keypad result with no reaction of the screen.

Code to reproduce

I am going to go ahead and put all of the code that is relevant. It is quite a lot and if I need to edit this post due to rules, please let me know.

Main.c LVGL code

All other initializations are done (display, flush, spi, lvgl, etc.). Text areas and other labels are currently displayed to screen. The interactivity is the only issue.

void initialize_screens(void){

    // Create input group
    lv_group_t * input_group = lv_group_create();
    lv_group_set_default(input_group);
    lv_indev_set_group(indev_keypad, input_group);

    ESP_LOGI(TAG, "Initializing Screens");
    /* Main input screen object */
    lv_obj_t * input_screen = lv_obj_create(NULL);
    lv_screen_load(input_screen);
    
    // Input Screen Items
    /* Create Inputs screen label at top center*/
    lv_obj_t * input_label = lv_label_create(input_screen);
    lv_label_set_text(input_label, "Inputs:");
    lv_obj_align(input_label, LV_ALIGN_TOP_MID, 0, 10);

    /* Create the Latitude input box */
    lv_obj_t * Lat_ta = lv_textarea_create(input_screen);
    lv_textarea_set_one_line(Lat_ta, true);
    lv_textarea_set_password_mode(Lat_ta, false);
    lv_textarea_set_placeholder_text(Lat_ta, "Decimal Deg. (N)");
    lv_obj_set_width(Lat_ta, lv_pct(40));
    lv_obj_align(Lat_ta, LV_ALIGN_LEFT_MID, 10, -40);
    lv_group_add_obj(input_group, Lat_ta);
    

    /* Create Latitude label */
    lv_obj_t * Lat_label = lv_label_create(input_screen);
    lv_label_set_text(Lat_label, "Latitude:");
    lv_obj_align_to(Lat_label, Lat_ta, LV_ALIGN_OUT_TOP_MID, 0, 0);


    /* Create the Longitude input box */
    lv_obj_t * Long_ta = lv_textarea_create(input_screen);
    lv_textarea_set_one_line(Long_ta, true);
    lv_textarea_set_password_mode(Long_ta, false);
    lv_textarea_set_placeholder_text(Long_ta, "Decimal Deg. (W)");
    lv_obj_set_width(Long_ta, lv_pct(40));
    lv_obj_align(Long_ta, LV_ALIGN_RIGHT_MID, -10, -40);
    lv_group_add_obj(input_group, Long_ta);

    /* Create Longitude label*/
    lv_obj_t * long_label = lv_label_create(input_screen);
    lv_label_set_text(long_label, "Longitude:");
    lv_obj_align_to(long_label, Long_ta, LV_ALIGN_OUT_TOP_MID, 0, 0);

    /* Create Enter button and label */
    lv_obj_t * Enter_button = lv_button_create(input_screen);
    lv_obj_align(Enter_button, LV_ALIGN_BOTTOM_MID, 0, -20);
    lv_group_add_obj(input_group, Enter_button);

    lv_obj_t * Enter_label = lv_label_create(Enter_button);
    lv_label_set_text(Enter_label, "Enter");
    lv_obj_center(Enter_label);

Indev keypad

This is the code for hardware initialization of the keypad, the indev initialization, the callback for the keypad, and the scanning of the keypad. It is a matrix keypad I have designed and created on a PCB and works properly. The code for the indev and callback are copied from one of the examples on the GitHub and seem to be working properly.

// Keypad.h

#ifndef KEYPAD_H
#define KEYPAD_H

#include "lvgl.h"

static lv_indev_t * indev_keypad;

void lv_port_indev_init(void);

#endif /*KEYPAD_H*/
// Keypad.c

#include <stdio.h>
#include <lvgl.h>
#include "driver/gpio.h"
#include "esp_log.h"
#include "Keypad.h"

#define NUM_ROWS 4 //INPUT to check
#define NUM_COLS 5 //OUTPUT to set

static void keypad_init(void);
static void keypad_read(lv_indev_t * indev, lv_indev_data_t * data);
static uint32_t keypad_get_key(void);

static const char *BTNTAG = "BTN";

static uint32_t row_gpio[NUM_ROWS] = {18, 8, 9, 17};
static uint32_t col_gpio[NUM_COLS] = {14, 13, 12, 11, 10};

static const uint32_t keys[NUM_ROWS][NUM_COLS] = {
    {37, 38, 39, 0, LV_KEY_UP},
    {34, 35, 36, 0, LV_KEY_DOWN},
    {31, 32, 33, 0, LV_KEY_LEFT},
    {LV_KEY_NEXT, LV_KEY_PREV, LV_KEY_BACKSPACE, LV_KEY_ENTER, LV_KEY_DOWN}
};

/*  Had to modify to new data type in declaration due to LVGL
    This is the mapping of the buttons. Will figure out later,
    just want to get navigation working right now

    {"7", "8", "9", "NA", "Up"},
    {"4", "5", "6", "NA", "Down"},
    {"1", "2", "3", "NA", "Left"},
    {".", "0", "Back", "Enter", "Right"}
*/

gpio_config_t config_pin = {
    .pin_bit_mask = 0,
    .mode = GPIO_MODE_INPUT,
    .pull_up_en = GPIO_PULLUP_DISABLE,
    .pull_down_en = GPIO_PULLDOWN_DISABLE,
    .intr_type = GPIO_INTR_DISABLE,
};

void lv_port_indev_init(void){

    keypad_init();

    ESP_LOGI(BTNTAG, "Creating Keypad LVGL Object");
    indev_keypad = lv_indev_create();
    lv_indev_set_type(indev_keypad, LV_INDEV_TYPE_KEYPAD);
    lv_indev_set_read_cb(indev_keypad, keypad_read);

}

static void keypad_init(void){

    ESP_LOGI(BTNTAG, "Initializing Keypad GPIO");

    for(int i = 0; i < NUM_COLS; i++){
        config_pin.pin_bit_mask = (1ULL << col_gpio[i]);
        config_pin.pull_up_en = GPIO_PULLUP_ENABLE;
        gpio_config(&config_pin);
    }

    for(int i = 0; i < NUM_ROWS; i++){
        config_pin.pin_bit_mask = (1ULL << row_gpio[i]);
        config_pin.pull_up_en = GPIO_PULLUP_DISABLE;
        gpio_config(&config_pin);
    }

};

static void keypad_read(lv_indev_t * indev, lv_indev_data_t * data){

    uint32_t act_key = keypad_get_key();
    data->key = act_key;

    if(act_key != 0){
        data->state = LV_INDEV_STATE_PRESSED;
        ESP_LOGI(BTNTAG, "%lu", act_key);

    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}

static uint32_t keypad_get_key(void){
    esp_log_level_set("gpio", ESP_LOG_ERROR);

    for(int i = 0; i < NUM_ROWS; i++){
        config_pin.pin_bit_mask = (1ULL << row_gpio[i]);
        config_pin.mode = GPIO_MODE_OUTPUT;
        gpio_config(&config_pin);
        gpio_set_level(row_gpio[i], 0);

        for(int j = 0; j < NUM_COLS; j++){
            int8_t level = gpio_get_level(col_gpio[j]);

            if(level == 0){
                config_pin.mode = GPIO_MODE_INPUT;
                gpio_config(&config_pin);
                return keys[i][j];
            }
        }
        config_pin.mode = GPIO_MODE_INPUT;
        gpio_config(&config_pin);
    }

    return 0;
}

I don’t have enough experience with this but I can clearly tell I am missing something obvious. If anyone knows what my issue is and could point me in the right direction, it would be greatly appreciated.

Screenshot and/or video

Hardware setup

Current screen output (cursor not seen in picture but is blinking in latitude box)

Putting everything in my main.c file seemed to fix the issue. I split up the driver stuff and left that in the keypad.c and header file, then brought over the indev stuff into the main.c file. This fixed everything. If anyone is doing something similar and would like to look at the code, please let me know.

Hi.
I see you’re doing great, could you help me with the keyboard?

I created 2 pages and switch between them using the keyboard.
I created a group, threw 4 tabs into it on the first page, 4 graphic buttons on the second page, created two groups. Tabviews in the first group, buttons in the second.
The question is this: when I press enter, I switch to another page using the function:
lv_menu_set_page(menu, main_page).

And how can I correctly refocus the group, or correctly switch to another page?
Since with a simple transition, that is, using this function, the old callback on the keys is intercepted.