Files
tactility/Tactility/Private/Tactility/service/gui/GuiService.h
T
Ken Van Hoeylandt e6e1dcd0ca Software keyboard refactored (#594)
Removed software keyboard in Tactility subproject (GuiService, Lvgl.cpp) and re-implemented it in TactilityKernel.
2026-07-28 00:04:09 +02:00

108 lines
3.2 KiB
C++

#pragma once
#include <Tactility/MessageQueue.h>
#include <Tactility/PubSub.h>
#include <Tactility/RecursiveMutex.h>
#include <Tactility/service/Service.h>
#include <Tactility/service/loader/Loader.h>
#include <Tactility/Semaphore.h>
#include <tactility/concurrent/dispatcher.h>
#include <lvgl/devices/keyboard.h>
namespace tt::service::gui {
/**
* Output a log warning if the current task is the GUI task.
* This is meant for code that should either create their own task or use a different task to execute on.
* @param[in] context a descriptive name or label that refers to the caller of this function
*/
void warnIfRunningOnGuiTask(const char* context);
class GuiService final : public Service {
// Thread and lock
Thread* thread = nullptr;
DispatcherHandle_t dispatcher = nullptr;
bool exitRequested = false;
RecursiveMutex mutex;
PubSub<loader::LoaderService::Event>::SubscriptionHandle loader_pubsub_subscription = nullptr;
// Signaled by hideApp() once App::onHide() has actually finished running on the GUI
// task. onLoaderEvent() blocks on this (still on the Loader thread, inside the
// synchronous pubsub publish() call) before returning from the ApplicationHiding
// branch, so LoaderService::transitionAppToState(Hiding) can't return - and therefore
// the immediately-following Destroyed transition (which unloads an ELF app's code via
// esp_elf_deinit) can't run - until onHide() has fully completed. Without this, the
// ELF's code/data can be unmapped while onHide() (and anything it spawned, like a
// camera capture task) is still executing it.
Semaphore hideDoneSem { 1, 0 };
// Layers and Canvas
lv_obj_t* appRootWidget = nullptr;
lv_obj_t* statusbarWidget = nullptr;
// App-specific
std::shared_ptr<app::AppInstance> appToRender = nullptr;
LvglSoftwareKeyboard software_keyboard = {};
bool isStarted = false;
static int32_t guiMain();
static void onGuiDispatch(void* context);
void onLoaderEvent(loader::LoaderService::Event event);
lv_obj_t* createAppViews(lv_obj_t* parent);
void redraw();
void lock() const {
check(mutex.lock(pdMS_TO_TICKS(1000)));
}
void unlock() const {
mutex.unlock();
}
void showApp(std::shared_ptr<app::AppInstance> app);
void hideApp();
public:
bool onStart(ServiceContext& service) override;
void onStop(ServiceContext& service) override;
/**
* Show the on-screen keyboard.
* @param[in] textarea the textarea to focus the input for
*/
void softwareKeyboardShow(lv_obj_t* textarea);
/**
* Hide the on-screen keyboard.
* Has no effect when the keyboard is not visible.
*/
void softwareKeyboardHide();
void keyboardAddTextArea(lv_obj_t* textarea);
/**
* 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 on-screen keyboard for text input inside our apps
*/
bool softwareKeyboardIsEnabled();
};
std::shared_ptr<GuiService> findService();
} // namespace