diff options
| author | jacqueline <me@jacqueline.id.au> | 2024-05-29 14:45:49 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2024-05-29 14:45:49 +1000 |
| commit | 2ff8eac022f397bb1aed28aca376fbe422fc8b3c (patch) | |
| tree | ae80d0d89a212b1badf1d971fc67e701a9e4e962 /src/tangara/input/feedback_tts.cpp | |
| parent | ef812a53e5a84665e74be8c46cb983edaa712b3f (diff) | |
| download | tangara-fw-2ff8eac022f397bb1aed28aca376fbe422fc8b3c.tar.gz | |
Start on TTS support by logging the data that will become TTS lines
Includes some misc cleanup of haptic double-triggering (or
non-triggering), since those cases all end up being TTS event
double-reporting, which to me crosses the threshold from "annoying" to
"usability issue"
Diffstat (limited to 'src/tangara/input/feedback_tts.cpp')
| -rw-r--r-- | src/tangara/input/feedback_tts.cpp | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/tangara/input/feedback_tts.cpp b/src/tangara/input/feedback_tts.cpp new file mode 100644 index 00000000..a9267aa8 --- /dev/null +++ b/src/tangara/input/feedback_tts.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2024 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "input/feedback_tts.hpp" + +#include <cstdint> +#include <variant> + +#include "lvgl/lvgl.h" + +#include "core/lv_event.h" +#include "core/lv_group.h" +#include "core/lv_obj.h" +#include "core/lv_obj_class.h" +#include "core/lv_obj_tree.h" +#include "extra/widgets/list/lv_list.h" +#include "tts/events.hpp" +#include "widgets/lv_label.h" + +#include "tts/events.hpp" +#include "tts/provider.hpp" + +namespace input { + +TextToSpeech::TextToSpeech(tts::Provider& tts) + : tts_(tts), last_obj_(nullptr) {} + +auto TextToSpeech::feedback(lv_group_t* group, uint8_t event_type) -> void { + if (group != last_group_) { + last_group_ = group; + last_obj_ = nullptr; + if (group) { + tts_.feed(tts::SimpleEvent::kContextChanged); + } + } + + if (group) { + lv_obj_t* focused = lv_group_get_focused(group); + if (focused == last_obj_) { + return; + } + + last_obj_ = focused; + if (focused != nullptr) { + describe(*focused); + } + } +} + +auto TextToSpeech::describe(lv_obj_t& obj) -> void { + if (lv_obj_check_type(&obj, &lv_btn_class) || + lv_obj_check_type(&obj, &lv_list_btn_class)) { + auto desc = findDescription(obj); + tts_.feed(tts::SelectionChanged{ + .new_selection = + tts::SelectionChanged::Selection{ + .description = desc, + .is_interactive = true, + }, + }); + } else { + auto desc = findDescription(obj); + tts_.feed(tts::SelectionChanged{ + .new_selection = + tts::SelectionChanged::Selection{ + .description = desc, + .is_interactive = false, + }, + }); + } +} + +auto TextToSpeech::findDescription(lv_obj_t& obj) + -> std::optional<std::string> { + if (lv_obj_get_child_cnt(&obj) > 0) { + for (size_t i = 0; i < lv_obj_get_child_cnt(&obj); i++) { + auto res = findDescription(*lv_obj_get_child(&obj, i)); + if (res) { + return res; + } + } + } + + if (lv_obj_check_type(&obj, &lv_label_class)) { + std::string text = lv_label_get_text(&obj); + if (!text.empty()) { + return text; + } + } + + return {}; +} + +} // namespace input |
