Fixes for keyboard

This commit is contained in:
Ken Van Hoeylandt 2026-08-09 16:17:42 +02:00
parent 7aac44bc35
commit 8a75bc501e
5 changed files with 56 additions and 3 deletions

View File

@ -575,6 +575,7 @@ static error_t tab5_keyboard_read_key(Device* device, KeyboardKeyData* data) {
static const KeyboardApi tab5_keyboard_api = { static const KeyboardApi tab5_keyboard_api = {
.read_key = tab5_keyboard_read_key, .read_key = tab5_keyboard_read_key,
.is_present = tab5_keyboard_is_attached,
}; };
// Defined in module.cpp - this driver is registered directly by m5stack-tab5's own module, // Defined in module.cpp - this driver is registered directly by m5stack-tab5's own module,

View File

@ -106,8 +106,11 @@ bool lvgl_hardware_keyboard_is_available() {
return false; return false;
} }
// TODO: Refactor the driver subsystem to so it does proper probing/releasing of such devices
// This work-around exists for the Tab5 keyboard driver.
bool present = keyboard_is_present(keyboard_device);
device_put(keyboard_device); device_put(keyboard_device);
return true; return present;
} }
void lvgl_hardware_keyboard_add_custom(lv_indev_t* indev) { void lvgl_hardware_keyboard_add_custom(lv_indev_t* indev) {
@ -137,9 +140,15 @@ static void textarea_show_keyboard(lv_event_t* event) {
} }
static void textarea_hide_keyboard(lv_event_t* event) { static void textarea_hide_keyboard(lv_event_t* event) {
if (last_software_keyboard.object != nullptr) { if (last_software_keyboard.object == nullptr) {
lvgl_software_keyboard_hide(&last_software_keyboard); return;
} }
// Only hide if the keyboard is actually bound to the textarea that triggered this
lv_obj_t* target = lv_event_get_current_target_obj(event);
if (lv_keyboard_get_textarea(last_software_keyboard.object) != target) {
return;
}
lvgl_software_keyboard_hide(&last_software_keyboard);
} }
void lvgl_software_keyboard_construct(LvglSoftwareKeyboard* keyboard, lv_obj_t* parent) { void lvgl_software_keyboard_construct(LvglSoftwareKeyboard* keyboard, lv_obj_t* parent) {
@ -187,6 +196,7 @@ void lvgl_keyboard_add_textarea(LvglSoftwareKeyboard* keyboard, lv_obj_t* textar
lv_obj_add_event_cb(textarea, textarea_show_keyboard, LV_EVENT_FOCUSED, nullptr); lv_obj_add_event_cb(textarea, textarea_show_keyboard, LV_EVENT_FOCUSED, nullptr);
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_DEFOCUSED, nullptr); lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_DEFOCUSED, nullptr);
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_READY, nullptr); lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_READY, nullptr);
lv_obj_add_event_cb(textarea, textarea_hide_keyboard, LV_EVENT_DELETE, nullptr);
} }
// lv_obj_t auto-remove themselves from the group when they are destroyed (last checked in LVGL 8.3) // lv_obj_t auto-remove themselves from the group when they are destroyed (last checked in LVGL 8.3)

View File

@ -42,6 +42,7 @@
#include <gps_meshtastic/module.h> #include <gps_meshtastic/module.h>
#include <crypt/module.h> #include <crypt/module.h>
#include <lvgl/devices/keyboard.h>
#include <lvgl/devices/pointer.h> #include <lvgl/devices/pointer.h>
#include <lvgl/lvgl.h> #include <lvgl/lvgl.h>
#include <lvgl/module.h> #include <lvgl/module.h>
@ -361,6 +362,9 @@ static void stopAppFromToolbar(lv_event_t*) {
app_event_emit(topmost, &event); app_event_emit(topmost, &event);
} }
// The on-screen keyboard widget itself, constructed during windowManagerScreenInit
static LvglSoftwareKeyboard softwareKeyboard { .object = nullptr };
static lv_obj_t* windowManagerScreenInit(lv_obj_t* root) { static lv_obj_t* windowManagerScreenInit(lv_obj_t* root) {
lv_obj_t* vertical_container = lv_obj_create(root); lv_obj_t* vertical_container = lv_obj_create(root);
lv_obj_set_size(vertical_container, LV_PCT(100), LV_PCT(100)); lv_obj_set_size(vertical_container, LV_PCT(100), LV_PCT(100));
@ -380,6 +384,11 @@ static lv_obj_t* windowManagerScreenInit(lv_obj_t* root) {
lv_obj_set_flex_grow(app_container, 1); lv_obj_set_flex_grow(app_container, 1);
lv_obj_set_flex_flow(app_container, LV_FLEX_FLOW_COLUMN); lv_obj_set_flex_flow(app_container, LV_FLEX_FLOW_COLUMN);
// Parented to root (not app_container/vertical_container) so it overlays on top of
// everything, including the statusbar, regardless of which app is showing. Hidden until a
// focused textarea shows it (see lvgl_keyboard_add_textarea()/textarea_show_keyboard()).
lvgl_software_keyboard_construct(&softwareKeyboard, root);
return app_container; return app_container;
} }
@ -440,6 +449,10 @@ static void onLvglStarted() {
} }
static void onLvglStopped() { static void onLvglStopped() {
if (softwareKeyboard.object != nullptr) {
lvgl_software_keyboard_destruct(&softwareKeyboard);
}
module_stop(&lvgl_window_manager_module); module_stop(&lvgl_window_manager_module);
lvgl::stopUsbHidInput(); lvgl::stopUsbHidInput();

View File

@ -66,6 +66,17 @@ struct KeyboardApi {
* @retval ERROR_NOT_SUPPORTED when this device has no backlight * @retval ERROR_NOT_SUPPORTED when this device has no backlight
*/ */
error_t (*get_backlight)(struct Device* device, struct Device** backlight_device); error_t (*get_backlight)(struct Device* device, struct Device** backlight_device);
/**
* @brief Optional: reports whether the keyboard is physically present right now. Only
* 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").
* @param[in] device the keyboard device
* @return true if physically attached/present
*/
bool (*is_present)(struct Device* device);
}; };
/** /**
@ -83,6 +94,14 @@ error_t keyboard_read_key(struct Device* device, struct KeyboardKeyData* data);
*/ */
error_t keyboard_get_backlight(struct Device* device, struct Device** backlight_device); error_t keyboard_get_backlight(struct Device* device, struct Device** backlight_device);
/**
* @brief Whether the keyboard device is physically present right now. True when the driver
* doesn't implement KeyboardApi::is_present (i.e. it's always physically present whenever its
* device is active) - see that field's doc comment.
* @param[in] device the keyboard device
*/
bool keyboard_is_present(struct Device* device);
extern const struct DeviceType KEYBOARD_TYPE; extern const struct DeviceType KEYBOARD_TYPE;
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -28,6 +28,16 @@ error_t keyboard_get_backlight(Device* device, Device** backlight_device) {
return KEYBOARD_DRIVER_API(driver)->get_backlight(device, backlight_device); return KEYBOARD_DRIVER_API(driver)->get_backlight(device, backlight_device);
} }
bool keyboard_is_present(Device* device) {
const auto* driver = device_get_driver(device);
if (KEYBOARD_DRIVER_API(driver)->is_present == nullptr) {
return true;
}
return KEYBOARD_DRIVER_API(driver)->is_present(device);
}
const DeviceType KEYBOARD_TYPE { const DeviceType KEYBOARD_TYPE {
.name = "keyboard" .name = "keyboard"
}; };