This commit is contained in:
Ken Van Hoeylandt 2026-08-22 23:34:32 +02:00
parent 670d6ab062
commit 0a2bab4e38
6 changed files with 24 additions and 8 deletions

View File

@ -35,8 +35,7 @@ properties:
silkscreen/keymap column order - see reverse-columns). 0 = no key at this position (e.g.
a blank matrix position, or a position handled as a modifier via shift-row/shift-col/
sym-row/sym-col instead). Non-zero bytes are sent as-is via KeyboardKeyData::key (a Unicode
codepoint - byte range covers Latin-1 - or an LVGL LV_KEY_* code for keys with no character
representation).
codepoint - byte range covers Latin-1 - for character and non-character keys).
keymap-uc:
type: array
element-type: uint8_t

View File

@ -43,7 +43,7 @@ LVGL's malloc/realloc/free can be routed through a custom backend instead of its
plain `malloc`. Three things are required:
**1. Select the backend.** On ESP32, via Kconfig (`sdkconfig`):
```
```sdkconfig
CONFIG_LV_USE_CUSTOM_MALLOC=y
```
On Simulator/POSIX, ESP-IDF's Kconfig doesn't apply - select it in `lv_conf.h` instead:

View File

@ -21,9 +21,12 @@ struct LvglSoftwareKeyboard {
* @warning Caller must hold the LVGL lock (see lvgl_lock() in lvgl_module.h) — call this from
* LvglModuleConfig.on_start, or after calling lvgl_lock() explicitly.
*
* @note Idempotent per device: if an indev is already bound to this device (see
* lvgl_keyboard_find_by_device()), that indev is returned instead of creating a second one.
*
* @param[in] device a device of type KEYBOARD_TYPE
* @param[in] display the display this indev should be associated with, or NULL to leave it unset
* @param[out] out_indev the created indev, valid only when ERROR_NONE is returned
* @param[out] out_indev the created (or already-existing) indev, valid only when ERROR_NONE is returned
* @retval ERROR_NONE on success
* @retval ERROR_INVALID_ARGUMENT if device or out_indev is NULL, or device is not of type KEYBOARD_TYPE
* @retval ERROR_OUT_OF_MEMORY if allocation failed

View File

@ -84,6 +84,18 @@ error_t lvgl_keyboard_add(struct Device* device, lv_display_t* display, lv_indev
return ERROR_INVALID_ARGUMENT;
}
// A device can reach here twice: lvgl_devices_attach()'s boot scan binds every KEYBOARD_TYPE
// device unconditionally (started or not), and a device that wasn't started yet at that point
// fires DEVICE_EVENT_STARTED later, driving a second call through
// KeyboardDeviceListener::onKeyboardDeviceStarted(). Without this check that would create a
// second indev for the same device, and onKeyboardDeviceStopped() only ever removes one of
// them, leaving the other dangling - polling a destructed device on the next LVGL tick.
lv_indev_t* existing = lvgl_keyboard_find_by_device(device);
if (existing != NULL) {
*out_indev = existing;
return ERROR_NONE;
}
auto* wrapper = new(std::nothrow) LvglDeviceContext(nullptr);
if (wrapper == NULL) {
return ERROR_OUT_OF_MEMORY;

View File

@ -191,13 +191,15 @@ lv_obj_t* statusbar_create(lv_obj_t* parent) {
update_icon(image, &(statusbar_data.icons[i]));
}
statusbar_data.mutex.unlock();
// Only now is statusbar->icons[] fully populated - see statusbar_constructor()'s comment for
// why the subscription can't be registered any earlier.
// why the subscription can't be registered any earlier. Subscribing before unlocking (rather
// than after) closes a narrow window where a concurrent statusbar_icon_add()/_remove()/
// _set_image()/_set_visibility() call could publish - and be missed by this instance - after
// the icons are populated but before it's subscribed.
statusbar->pubsub_subscription = statusbar_data.pubsub->subscribe([statusbar](auto) {
statusbar_pubsub_event(statusbar);
});
statusbar_data.mutex.unlock();
return obj;
}

View File

@ -115,7 +115,7 @@ struct KeyboardApi {
/**
* @brief Optional: reports whether the keyboard is physically present right now. Only
* meaningful for hot-pluggable/detachable keyboarcardputer_keyboard.cppds (e.g. a removable accessory) whose
* meaningful for hot-pluggable/detachable keyboards (e.g. a removable accessory) whose
* kernel device is constructed and started once at boot regardless of physical attachment -
* leave NULL for a keyboard that's always physically present whenever its device is active
* (the common case; callers must treat NULL the same as "always present").