From 618f557a163cf513a8071368f88dfe01fc9eb3b2 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Sun, 28 Jan 2024 00:04:47 +0100 Subject: [PATCH] Simplify keyboard support (#22) * simplify keyboard support * removed cleanup code as it wasn't necessary * improved docs --- .../system/wifi_connect/wifi_connect_view.c | 30 +------- tactility/src/hardware.c | 4 +- tactility/src/services/gui/gui.c | 41 ++--------- tactility/src/services/gui/gui.h | 13 +++- tactility/src/services/gui/gui_draw.c | 8 ++- tactility/src/services/gui/gui_i.h | 10 ++- tactility/src/services/gui/gui_keyboard.c | 70 +++++++++++++++++++ tactility/src/tactility.c | 2 +- tactility/src/ui/lvgl_keypad.h | 22 ++++++ 9 files changed, 126 insertions(+), 74 deletions(-) create mode 100644 tactility/src/services/gui/gui_keyboard.c diff --git a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.c b/tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.c index fdc70a9a..0b3e6399 100644 --- a/tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.c +++ b/tactility-esp/src/apps/system/wifi_connect/wifi_connect_view.c @@ -4,7 +4,6 @@ #include "lvgl.h" #include "services/gui/gui.h" #include "services/wifi/wifi_credentials.h" -#include "ui/lvgl_keypad.h" #include "ui/spacer.h" #include "ui/style.h" #include "wifi_connect.h" @@ -13,15 +12,6 @@ #define TAG "wifi_connect" -static void show_keyboard(lv_event_t* event) { - gui_keyboard_show(event->current_target); - lv_obj_scroll_to_view(event->current_target, LV_ANIM_ON); -} - -static void hide_keyboard(TT_UNUSED lv_event_t* event) { - gui_keyboard_hide(); -} - static void on_connect(lv_event_t* event) { WifiConnect* wifi = (WifiConnect*)event->user_data; WifiConnectView* view = &wifi->view; @@ -104,14 +94,8 @@ void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent) { wifi_connect_view_create_bottom_buttons(wifi, parent); - if (gui_keyboard_is_enabled()) { - lv_obj_add_event_cb(view->ssid_textarea, show_keyboard, LV_EVENT_FOCUSED, NULL); - lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL); - lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_READY, NULL); - lv_obj_add_event_cb(view->password_textarea, show_keyboard, LV_EVENT_FOCUSED, NULL); - lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL); - lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_READY, NULL); - } + gui_keyboard_add_textarea(view->ssid_textarea); + gui_keyboard_add_textarea(view->password_textarea); // Init from app parameters Bundle* _Nullable bundle = tt_app_get_parameters(app); @@ -126,18 +110,10 @@ void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent) { lv_textarea_set_text(view->password_textarea, password); } } - - // Hardware keyboard("keypad") requires a group - view->group = lv_group_create(); - lv_group_add_obj(view->group, view->ssid_textarea); - lv_group_add_obj(view->group, view->password_textarea); - tt_lvgl_keypad_activate(view->group); } void wifi_connect_view_destroy(TT_UNUSED WifiConnectView* view) { - // Cleanup keypad group - tt_lvgl_keypad_deactivate(); - lv_group_del(view->group); + // NO-OP } void wifi_connect_view_update( diff --git a/tactility/src/hardware.c b/tactility/src/hardware.c index 256a4249..5ef43855 100644 --- a/tactility/src/hardware.c +++ b/tactility/src/hardware.c @@ -1,6 +1,8 @@ -#include "check.h" #include "hardware_i.h" +#include "check.h" +#include "lvgl.h" + #define TAG "hardware" void tt_hardware_init(const HardwareConfig* config) { diff --git a/tactility/src/services/gui/gui.c b/tactility/src/services/gui/gui.c index 375e2fc7..418cd53c 100644 --- a/tactility/src/services/gui/gui.c +++ b/tactility/src/services/gui/gui.c @@ -16,7 +16,7 @@ void gui_redraw(Gui*); static int32_t gui_main(void*); -static Gui* gui = NULL; +Gui* gui = NULL; Gui* gui_alloc() { Gui* instance = malloc(sizeof(Gui)); @@ -32,6 +32,7 @@ Gui* gui_alloc() { instance->keyboard = NULL; tt_check(tt_lvgl_lock(1000 / portTICK_PERIOD_MS)); + instance->keyboard_group = lv_group_create(); instance->lvgl_parent = lv_scr_act(); tt_lvgl_unlock(); @@ -42,6 +43,11 @@ void gui_free(Gui* instance) { tt_assert(instance != NULL); tt_thread_free(instance->thread); tt_mutex_free(instance->mutex); + + tt_check(tt_lvgl_lock(1000 / portTICK_PERIOD_MS)); + lv_group_del(instance->keyboard_group); + tt_lvgl_unlock(); + free(instance); } @@ -71,39 +77,6 @@ void gui_show_app(App app, ViewPortShowCallback on_show, ViewPortHideCallback on gui_request_draw(); } -void gui_keyboard_show(lv_obj_t* textarea) { - if (gui->keyboard) { - gui_lock(); - - lv_obj_clear_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN); - lv_keyboard_set_textarea(gui->keyboard, textarea); - - if (gui->toolbar) { - lv_obj_add_flag(gui->toolbar, LV_OBJ_FLAG_HIDDEN); - } - - gui_unlock(); - } -} - -void gui_keyboard_hide() { - if (gui->keyboard) { - gui_lock(); - - lv_obj_add_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN); - - if (gui->toolbar) { - lv_obj_clear_flag(gui->toolbar, LV_OBJ_FLAG_HIDDEN); - } - - gui_unlock(); - } -} - -bool gui_keyboard_is_enabled() { - return !tt_lvgl_keypad_is_available() || TT_CONFIG_FORCE_ONSCREEN_KEYBOARD; -} - void gui_hide_app() { gui_lock(); ViewPort* view_port = gui->app_view_port; diff --git a/tactility/src/services/gui/gui.h b/tactility/src/services/gui/gui.h index f9ed7226..3d713734 100644 --- a/tactility/src/services/gui/gui.h +++ b/tactility/src/services/gui/gui.h @@ -40,14 +40,21 @@ void gui_keyboard_show(lv_obj_t* textarea); void gui_keyboard_hide(); /** - * This function is to facilitate hardware keyboards like the one on Lilygo T-Deck. - * The software keyboard is only shown when both of these conditions are true: + * The on-screen keyboard is only shown when both of these conditions are true: * - there is no hardware keyboard * - TT_CONFIG_FORCE_ONSCREEN_KEYBOARD is set to true in tactility_config.h - * @return if we should show a keyboard for text input inside our apps + * @return if we should show a on-screen keyboard for text input inside our apps */ bool gui_keyboard_is_enabled(); +/** + * Glue code for the on-screen keyboard and the hardware keyboard: + * - Attach automatic hide/show parameters for the on-screen keyboard. + * - Registers the textarea to the default lv_group_t for hardware keyboards. + * @param textarea + */ +void gui_keyboard_add_textarea(lv_obj_t* textarea); + #ifdef __cplusplus } #endif diff --git a/tactility/src/services/gui/gui_draw.c b/tactility/src/services/gui/gui_draw.c index f41a2fd0..e88771ce 100644 --- a/tactility/src/services/gui/gui_draw.c +++ b/tactility/src/services/gui/gui_draw.c @@ -49,8 +49,12 @@ static lv_obj_t* create_app_views(Gui* gui, lv_obj_t* parent, App app) { lv_obj_set_width(child_container, LV_PCT(100)); lv_obj_set_flex_grow(child_container, 1); - gui->keyboard = lv_keyboard_create(vertical_container); - lv_obj_add_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN); + if (gui_keyboard_is_enabled()) { + gui->keyboard = lv_keyboard_create(vertical_container); + lv_obj_add_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN); + } else { + gui->keyboard = NULL; + } return child_container; } diff --git a/tactility/src/services/gui/gui_i.h b/tactility/src/services/gui/gui_i.h index 595e17dd..e0ddc0ef 100644 --- a/tactility/src/services/gui/gui_i.h +++ b/tactility/src/services/gui/gui_i.h @@ -27,16 +27,14 @@ struct Gui { lv_obj_t* _Nullable toolbar; lv_obj_t* _Nullable keyboard; + lv_group_t* keyboard_group; }; -/** Update GUI, request redraw - */ +/** Update GUI, request redraw */ void gui_request_draw(); -/** Lock GUI - */ +/** Lock GUI */ void gui_lock(); -/** Unlock GUI - */ +/** Unlock GUI */ void gui_unlock(); diff --git a/tactility/src/services/gui/gui_keyboard.c b/tactility/src/services/gui/gui_keyboard.c new file mode 100644 index 00000000..f18f47e0 --- /dev/null +++ b/tactility/src/services/gui/gui_keyboard.c @@ -0,0 +1,70 @@ +#include "gui_i.h" + +#include "tactility_config.h" +#include "ui/lvgl_keypad.h" +#include "ui/lvgl_sync.h" + +extern Gui* gui; + +static void show_keyboard(lv_event_t* event) { + gui_keyboard_show(event->current_target); + lv_obj_scroll_to_view(event->current_target, LV_ANIM_ON); +} + +static void hide_keyboard(TT_UNUSED lv_event_t* event) { + gui_keyboard_hide(); +} + +bool gui_keyboard_is_enabled() { + return !tt_lvgl_keypad_is_available() || TT_CONFIG_FORCE_ONSCREEN_KEYBOARD; +} + +void gui_keyboard_show(lv_obj_t* textarea) { + gui_lock(); + + if (gui->keyboard) { + gui_lock(); + + lv_obj_clear_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN); + lv_keyboard_set_textarea(gui->keyboard, textarea); + + if (gui->toolbar) { + lv_obj_add_flag(gui->toolbar, LV_OBJ_FLAG_HIDDEN); + } + + } + + gui_unlock(); +} + +void gui_keyboard_hide() { + gui_lock(); + + if (gui->keyboard) { + lv_obj_add_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN); + if (gui->toolbar) { + lv_obj_clear_flag(gui->toolbar, LV_OBJ_FLAG_HIDDEN); + } + } + + gui_unlock(); +} + +void gui_keyboard_add_textarea(lv_obj_t* textarea) { + gui_lock(); + tt_check(tt_lvgl_lock(0), "lvgl should already be locked before calling this method"); + + if (gui_keyboard_is_enabled()) { + lv_obj_add_event_cb(textarea, show_keyboard, LV_EVENT_FOCUSED, NULL); + lv_obj_add_event_cb(textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL); + lv_obj_add_event_cb(textarea, hide_keyboard, LV_EVENT_READY, NULL); + } + + // lv_obj_t auto-remove themselves from the group when they are destroyed (last checked in LVGL 8.3) + lv_group_add_obj(gui->keyboard_group, textarea); + + tt_lvgl_keypad_activate(gui->keyboard_group); + + tt_lvgl_unlock(); + gui_unlock(); +} diff --git a/tactility/src/tactility.c b/tactility/src/tactility.c index d085ae71..9ec13b4e 100644 --- a/tactility/src/tactility.c +++ b/tactility/src/tactility.c @@ -84,7 +84,7 @@ TT_UNUSED void tt_init(const Config* config) { tt_hardware_init(config->hardware); // Note: the order of starting apps and services is critical! - // System services are registered first so they can be used by the apps + // System services are registered first so the apps below can use them register_and_start_system_services(); // Then we register system apps. They are not used/started yet. register_system_apps(); diff --git a/tactility/src/ui/lvgl_keypad.h b/tactility/src/ui/lvgl_keypad.h index c531c4a4..2bc33e70 100644 --- a/tactility/src/ui/lvgl_keypad.h +++ b/tactility/src/ui/lvgl_keypad.h @@ -1,3 +1,6 @@ +/** + * This code relates to the hardware keyboard support also known as "keypads" in LVGL. + */ #pragma once #include "lvgl.h" @@ -6,9 +9,28 @@ extern "C" { #endif +/** + * @return true if LVGL is configured with a keypad + */ bool tt_lvgl_keypad_is_available(); + +/** + * Set the keypad. + * @param device the keypad device + */ void tt_lvgl_keypad_set_indev(lv_indev_t* device); + +/** + * Activate the keypad for a widget group. + * @param group + */ void tt_lvgl_keypad_activate(lv_group_t* group); + +/** + * Deactivate the keypad for the current widget group (if any). + * You don't have to call this after calling _activate() because widget + * cleanup automatically removes itself from the group it belongs to. + */ void tt_lvgl_keypad_deactivate(); #ifdef __cplusplus