feat(indev): implement key remapping (#8455) (#8981)
Arduino Lint / lint (push) Has been cancelled
Build Examples with C++ Compiler / build-examples (push) Has been cancelled
MicroPython CI / Build esp32 port (push) Has been cancelled
MicroPython CI / Build rp2 port (push) Has been cancelled
MicroPython CI / Build stm32 port (push) Has been cancelled
MicroPython CI / Build unix port (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Has been cancelled
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Has been cancelled
C/C++ CI / Build ESP IDF ESP32S3 (push) Has been cancelled
C/C++ CI / Run tests with 32bit build (push) Has been cancelled
C/C++ CI / Run tests with 64bit build (push) Has been cancelled
BOM Check / bom-check (push) Has been cancelled
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Has been cancelled
Verify the widget property name / verify-property-name (push) Has been cancelled
Verify code formatting / verify-formatting (push) Has been cancelled
Compare file templates with file names / template-check (push) Has been cancelled
Build docs / build-and-deploy (push) Has been cancelled
Test API JSON generator / Test API JSON (push) Has been cancelled
Install LVGL using CMake / build-examples (push) Has been cancelled
Check Makefile / Build using Makefile (push) Has been cancelled
Check Makefile for UEFI / Build using Makefile for UEFI (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/benchmark_results_comment/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/filter_docker_logs/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Script Check (scripts/perf/tests/serialize_results/test.sh) (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 32b - lv_conf_perf32b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark 64b - lv_conf_perf64b (push) Has been cancelled
Emulated Performance Test / ARM Emulated Benchmark - Save PR Number (push) Has been cancelled
Hardware Performance Test / Hardware Performance Benchmark (push) Has been cancelled
Hardware Performance Test / HW Benchmark - Save PR Number (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_32B - Ubuntu (push) Has been cancelled
Performance Tests CI / Perf Tests OPTIONS_TEST_PERF_64B - Ubuntu (push) Has been cancelled
Port repo release update / run-release-branch-updater (push) Has been cancelled
Verify Font License / verify-font-license (push) Has been cancelled
Verify Kconfig / verify-kconfig (push) Has been cancelled

Co-authored-by: Jean THOMAS <jean@lambdaconcept.com>
This commit is contained in:
Jean THOMAS
2025-10-31 07:47:45 +01:00
committed by GitHub
co-authored by Jean THOMAS
parent 262a125dac
commit cf38b6f873
5 changed files with 166 additions and 0 deletions
@@ -87,3 +87,41 @@ The most important special keys in your :cpp:func:`read_cb` function are:
You should translate some of the read keys to these special keys to support navigation
in a group and interact with selected widgets.
Key remapping
*************
Some applications require assigning physical buttons to multiple key events depending
on the context: arrow keys may be used in a screen to navigate across widgets, and
used to interact with one widget in another screen. Key remapping functionality of
indev can be used to implement this behavior.
You must first define a remapping callback, then invoke
:cpp:func:`lv_indev_set_key_remap_cb` to enable it.
.. code-block:: c
lv_key_t remap_left_right_into_prev_next(lv_indev_t * indev, lv_key_t key)
{
LV_UNUSED(indev);
switch (key) {
case LV_KEY_LEFT:
return LV_KEY_PREV;
case LV_KEY_RIGHT:
return LV_KEY_NEXT;
default:
return key;
}
}
.. code-block:: c
/* in your setup code */
lv_indev_set_key_remap_cb(indev, remap_left_right_into_prev_next);
/* later, to disable remapping */
lv_indev_set_key_remap_cb(indev, NULL);
.. note::
The remap callback is invoked only for keypad input devices. It will not remap keys from other input device types.
+16
View File
@@ -141,6 +141,7 @@ lv_indev_t * lv_indev_create(void)
indev->gesture_limit = LV_INDEV_DEF_GESTURE_LIMIT;
indev->gesture_min_velocity = LV_INDEV_DEF_GESTURE_MIN_VELOCITY;
indev->rotary_sensitivity = LV_INDEV_DEF_ROTARY_SENSITIVITY;
indev->key_remap_cb = NULL;
#if LV_USE_GESTURE_RECOGNITION
lv_indev_gesture_init(indev);
@@ -674,6 +675,16 @@ lv_result_t lv_indev_send_event(lv_indev_t * indev, lv_event_code_t code, void *
return lv_event_push_and_send(&indev->event_list, code, indev, param);
}
void lv_indev_set_key_remap_cb(lv_indev_t * indev, lv_indev_key_remap_cb_t remap_cb)
{
if(!indev) {
LV_LOG_WARN("Can't remap key on a NULL indev");
return;
}
indev->key_remap_cb = remap_cb;
}
/**********************
* STATIC FUNCTIONS
**********************/
@@ -762,6 +773,11 @@ static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
i->keypad.last_state = LV_INDEV_STATE_RELEASED; /*To skip the processing of release*/
}
/* Remap key using callback */
if(i->key_remap_cb) {
data->key = i->key_remap_cb(i, data->key);
}
/*Save the last key. *It must be done here else `lv_indev_get_key` will return the last key in events*/
uint32_t prev_key = i->keypad.last_key;
i->keypad.last_key = data->key;
+10
View File
@@ -77,6 +77,9 @@ typedef struct {
typedef void (*lv_indev_read_cb_t)(lv_indev_t * indev, lv_indev_data_t * data);
/** Indev key remapping callback */
typedef lv_key_t (*lv_indev_key_remap_cb_t)(lv_indev_t * indev, lv_key_t key);
/**********************
* GLOBAL PROTOTYPES
**********************/
@@ -442,6 +445,13 @@ uint32_t lv_indev_remove_event_cb_with_user_data(lv_indev_t * indev, lv_event_cb
*/
lv_result_t lv_indev_send_event(lv_indev_t * indev, lv_event_code_t code, void * param);
/**
* Set key remapping callback (LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an indev
* @param remap_cb remapping function callback. Use NULL to disable callback.
*/
void lv_indev_set_key_remap_cb(lv_indev_t * indev, lv_indev_key_remap_cb_t remap_cb);
/**********************
* MACROS
**********************/
+3
View File
@@ -123,6 +123,9 @@ struct _lv_indev_t {
lv_event_list_t event_list;
lv_anim_t * scroll_throw_anim;
/**< Key remapping callback */
lv_indev_key_remap_cb_t key_remap_cb;
#if LV_USE_GESTURE_RECOGNITION
lv_indev_gesture_recognizer_t recognizers[LV_INDEV_GESTURE_CNT];
lv_indev_gesture_type_t cur_gesture;
@@ -0,0 +1,99 @@
#if LV_BUILD_TEST
#include "../lvgl.h"
#include "unity/unity.h"
#include <assert.h>
#define MAX_KEYS 6
struct key_buffer {
size_t count;
lv_key_t keys[MAX_KEYS];
};
static void key_buffer_add(struct key_buffer * key_buffer, lv_key_t key)
{
assert(key_buffer->count + 1 <= MAX_KEYS);
key_buffer->keys[key_buffer->count++] = key;
}
void setUp(void)
{
/* Function run before every test */
}
void tearDown(void)
{
/* Function run after every test */
lv_obj_clean(lv_screen_active());
}
static void event_cb(lv_event_t * e)
{
struct key_buffer * key_buffer = lv_event_get_user_data(e);
switch(lv_event_get_code(e)) {
case LV_EVENT_KEY:
key_buffer_add(key_buffer, lv_indev_get_key(lv_indev_active()));
break;
default:
break;
}
}
static lv_key_t remap_cb(lv_indev_t * i, lv_key_t key)
{
LV_UNUSED(i);
switch((int)key) {
case 'a':
return LV_KEY_LEFT;
case LV_KEY_ESC:
return 'Z';
default:
return key;
}
}
void test_indev_key_remap(void)
{
struct key_buffer key_buffer = {
.count = 0,
};
lv_group_t * group = lv_group_create();
lv_indev_t * indev = lv_test_indev_get_indev(LV_INDEV_TYPE_KEYPAD);
lv_indev_set_group(indev, group);
lv_obj_t * btn = lv_button_create(lv_screen_active());
lv_obj_set_size(btn, 100, 100);
lv_obj_add_event_cb(btn, event_cb, LV_EVENT_ALL, &key_buffer);
lv_group_add_obj(group, btn);
lv_test_key_hit('a');
lv_test_key_hit(LV_KEY_ESC);
/* Remap 'a' -> LV_KEY_LEFT, LV_KEY_ESC -> 'Z' */
lv_indev_set_key_remap_cb(indev, remap_cb);
lv_test_key_hit('a');
lv_test_key_hit(LV_KEY_ESC);
/* Disable remapping */
lv_indev_set_key_remap_cb(indev, NULL);
lv_test_key_hit('a');
lv_test_key_hit(LV_KEY_ESC);
TEST_ASSERT_EQUAL_UINT32(6, key_buffer.count);
TEST_ASSERT_EQUAL_UINT32('a', key_buffer.keys[0]);
TEST_ASSERT_EQUAL_UINT32(LV_KEY_ESC, key_buffer.keys[1]);
TEST_ASSERT_EQUAL_UINT32(LV_KEY_LEFT, key_buffer.keys[2]);
TEST_ASSERT_EQUAL_UINT32('Z', key_buffer.keys[3]);
TEST_ASSERT_EQUAL_UINT32('a', key_buffer.keys[4]);
TEST_ASSERT_EQUAL_UINT32(LV_KEY_ESC, key_buffer.keys[5]);
}
#endif