diff --git a/dts/bindings/input/zephyr,lvgl-keypad-input.yaml b/dts/bindings/input/zephyr,lvgl-keypad-input.yaml new file mode 100644 index 00000000000..2728d0e710c --- /dev/null +++ b/dts/bindings/input/zephyr,lvgl-keypad-input.yaml @@ -0,0 +1,41 @@ +# Copyright 2023 Fabian Blatz +# SPDX-License-Identifier: Apache-2.0 + +description: | + LVGL keypad indev pseudo-device + + Listens for input events and routes the + lv_indev_data_t to the underlying keypad lv_indev_t managed by LVGL. + + The property input-codes can be used to setup a mapping of input codes + to the lvgl keys. There are lvgl keys that have a special function: + https://docs.lvgl.io/master/overview/indev.html#keys. + + The pseudo device can be associated to a specific device to listen only + for events from that device. Example configuration: + + #include + + keypad { + compatible = "zephyr,lvgl-keypad-input"; + input = <&buttons>; + input-codes = ; + lvgl-codes = ; + }; + +compatible: "zephyr,lvgl-keypad-input" + +include: zephyr,lvgl-common-input.yaml + +properties: + input-codes: + type: array + required: true + description: | + Array of input event key codes (INPUT_KEY_* or INPUT_BTN_*). + + lvgl-codes: + type: array + required: true + description: | + Array of mapped lvgl keys. diff --git a/include/zephyr/dt-bindings/lvgl/lvgl.h b/include/zephyr/dt-bindings/lvgl/lvgl.h new file mode 100644 index 00000000000..09ad0ae361b --- /dev/null +++ b/include/zephyr/dt-bindings/lvgl/lvgl.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ + +/* Predefined keys to control the focused object. + * Values taken from enum _lv_key_t in lv_group.h + */ +#define LV_KEY_UP 17 +#define LV_KEY_DOWN 18 +#define LV_KEY_RIGHT 19 +#define LV_KEY_LEFT 20 +#define LV_KEY_ESC 27 +#define LV_KEY_DEL 127 +#define LV_KEY_BACKSPACE 8 +#define LV_KEY_ENTER 10 +#define LV_KEY_NEXT 9 +#define LV_KEY_PREV 11 +#define LV_KEY_HOME 2 +#define LV_KEY_END 3 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_LVGL_LVGL_H_ */ diff --git a/modules/lvgl/CMakeLists.txt b/modules/lvgl/CMakeLists.txt index 51eb2bd11da..9f119b016eb 100644 --- a/modules/lvgl/CMakeLists.txt +++ b/modules/lvgl/CMakeLists.txt @@ -228,6 +228,7 @@ zephyr_library_sources_ifdef(CONFIG_LV_Z_POINTER_KSCAN input/lvgl_pointer_kscan zephyr_library_sources_ifdef(CONFIG_LV_Z_POINTER_INPUT input/lvgl_pointer_input.c) zephyr_library_sources_ifdef(CONFIG_LV_Z_BUTTON_INPUT input/lvgl_button_input.c) zephyr_library_sources_ifdef(CONFIG_LV_Z_ENCODER_INPUT input/lvgl_encoder_input.c) +zephyr_library_sources_ifdef(CONFIG_LV_Z_KEYPAD_INPUT input/lvgl_keypad_input.c) zephyr_library_link_libraries(LVGL) target_link_libraries(LVGL INTERFACE zephyr_interface) diff --git a/modules/lvgl/Kconfig.input b/modules/lvgl/Kconfig.input index b6cbdad0c28..4f76643aa86 100644 --- a/modules/lvgl/Kconfig.input +++ b/modules/lvgl/Kconfig.input @@ -77,4 +77,17 @@ config LV_Z_ENCODER_INPUT_MSGQ_COUNT help Size of the encoder message queue buffering input events. +config LV_Z_KEYPAD_INPUT + bool "Input lvgl keypad" + default y + depends on INPUT + depends on DT_HAS_ZEPHYR_LVGL_KEYPAD_INPUT_ENABLED + +config LV_Z_KEYPAD_INPUT_MSGQ_COUNT + int "Input keypad queue message count" + default 4 + depends on LV_Z_KEYPAD_INPUT + help + Size of the keypad message queue buffering input events. + endmenu diff --git a/modules/lvgl/include/lvgl_keypad_input.h b/modules/lvgl/include/lvgl_keypad_input.h new file mode 100644 index 00000000000..f1d6e925f12 --- /dev/null +++ b/modules/lvgl/include/lvgl_keypad_input.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ +#define ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int lvgl_keypad_input_init(const struct device *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_MODULES_LVGL_LVGL_KEYPAD_INPUT_H_ */ diff --git a/modules/lvgl/input/lvgl_common_input.c b/modules/lvgl/input/lvgl_common_input.c index 2894538c62b..2f2e1d32bd1 100644 --- a/modules/lvgl/input/lvgl_common_input.c +++ b/modules/lvgl/input/lvgl_common_input.c @@ -12,6 +12,7 @@ #include "lvgl_pointer_input.h" #include "lvgl_button_input.h" #include "lvgl_encoder_input.h" +#include "lvgl_keypad_input.h" LOG_MODULE_DECLARE(lvgl, CONFIG_LV_Z_LOG_LEVEL); @@ -90,5 +91,9 @@ int lvgl_init_input_devices(void) lvgl_encoder_input_init); #endif /* CONFIG_LV_Z_ENCODER_INPUT */ +#ifdef CONFIG_LV_Z_KEYPAD_INPUT + DT_FOREACH_STATUS_OKAY_VARGS(zephyr_lvgl_keypad_input, LV_DEV_INIT, lvgl_keypad_input_init); +#endif /* CONFIG_LV_Z_KEYPAD_INPUT */ + return 0; } diff --git a/modules/lvgl/input/lvgl_keypad_input.c b/modules/lvgl/input/lvgl_keypad_input.c new file mode 100644 index 00000000000..08fd8a37a4e --- /dev/null +++ b/modules/lvgl/input/lvgl_keypad_input.c @@ -0,0 +1,75 @@ +/* + * Copyright 2023 Fabian Blatz + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT zephyr_lvgl_keypad_input + +#include "lvgl_common_input.h" +#include "lvgl_keypad_input.h" +#include + +#include + +LOG_MODULE_DECLARE(lvgl); + +struct lvgl_keypad_input_config { + struct lvgl_common_input_config common_config; /* Needs to be first member */ + const uint16_t *input_codes; + const uint16_t *lvgl_codes; + uint8_t num_codes; +}; + +static void lvgl_keypad_process_event(const struct device *dev, struct input_event *evt) +{ + struct lvgl_common_input_data *data = dev->data; + const struct lvgl_keypad_input_config *cfg = dev->config; + uint8_t i; + + for (i = 0; i < cfg->num_codes; i++) { + if (evt->code == cfg->input_codes[i]) { + data->pending_event.key = cfg->lvgl_codes[i]; + break; + } + } + + if (i == cfg->num_codes) { + LOG_WRN("Ignored input event: %u", evt->code); + return; + } + + data->pending_event.state = evt->value ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + if (k_msgq_put(cfg->common_config.event_msgq, &data->pending_event, + K_NO_WAIT) != 0) { + LOG_WRN("Could not put input data into keypad queue"); + } +} + +int lvgl_keypad_input_init(const struct device *dev) +{ + return lvgl_input_register_driver(LV_INDEV_TYPE_KEYPAD, dev); +} + +#define ASSERT_PROPERTIES(inst) \ + BUILD_ASSERT(DT_INST_PROP_LEN(inst, input_codes) == DT_INST_PROP_LEN(inst, lvgl_codes), \ + "Property input-codes must have the same length as lvgl-codes."); + +#define LVGL_KEYPAD_INPUT_DEFINE(inst) \ + ASSERT_PROPERTIES(inst); \ + LVGL_INPUT_DEFINE(inst, keypad, CONFIG_LV_Z_KEYPAD_INPUT_MSGQ_COUNT, \ + lvgl_keypad_process_event); \ + static const uint16_t lvgl_keypad_input_codes_##inst[] = DT_INST_PROP(inst, input_codes); \ + static const uint16_t lvgl_keypad_lvgl_codes_##inst[] = DT_INST_PROP(inst, lvgl_codes); \ + static const struct lvgl_keypad_input_config lvgl_keypad_input_config_##inst = { \ + .common_config.event_msgq = &LVGL_INPUT_EVENT_MSGQ(inst, keypad), \ + .input_codes = lvgl_keypad_input_codes_##inst, \ + .lvgl_codes = lvgl_keypad_lvgl_codes_##inst, \ + .num_codes = DT_INST_PROP_LEN(inst, input_codes), \ + }; \ + static struct lvgl_common_input_data lvgl_common_input_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &lvgl_common_input_data_##inst, \ + &lvgl_keypad_input_config_##inst, POST_KERNEL, \ + CONFIG_INPUT_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(LVGL_KEYPAD_INPUT_DEFINE)