fix: support escape navigation on UI pages

This commit is contained in:
liu weikai committed 2026-06-28 00:10:30 +08:00
1 parent b331ed7da7
commit 3dee080890
18 files changed
+166 -48

No files matched your search

@@ -573,7 +573,7 @@ static void root_key_event_cb(lv_event_t* e)
if (!binding_alive(binding)) return;
const uint32_t key = lv_event_get_key(e);
if (key == LV_KEY_BACKSPACE)
if (key == LV_KEY_BACKSPACE || key == LV_KEY_ESC)
{
if (lv_obj_t* back = get_top_back_button(binding))
{
@@ -584,13 +584,6 @@ static void root_key_event_cb(lv_event_t* e)
if (!is_encoder_active()) return;
if (key == LV_KEY_ESC)
{
set_column(binding, FocusColumn::Filter);
rebind_by_column(binding);
return;
}
if (key != LV_KEY_ENTER) return;
lv_obj_t* focused = binding->group ? lv_group_get_focused(binding->group) : nullptr;
@@ -558,6 +558,16 @@ void ChatComposeScreen::on_key(lv_event_t* e)
}
uint32_t key = lv_event_get_key(e);
if (key == LV_KEY_ESC)
{
if (screen->back_cb_)
{
screen->schedule_back_async();
}
lv_event_stop_processing(e);
return;
}
if (key == LV_KEY_ENTER && screen->impl_->w.send_btn)
{
lv_obj_t* target = static_cast<lv_obj_t*>(lv_event_get_target(e));
@@ -27,7 +27,7 @@ static void on_msg_list_key(lv_event_t* e)
if (!screen || !screen->isAlive()) return;
uint32_t key = lv_event_get_key(e);
if (key == LV_KEY_BACKSPACE)
if (key == LV_KEY_BACKSPACE || key == LV_KEY_ESC)
{
if (lv_obj_t* back_btn = screen->getBackBtn())
{
@@ -76,7 +76,7 @@ static void on_backspace_key(lv_event_t* e)
auto* screen = static_cast<ChatConversationScreen*>(lv_event_get_user_data(e));
if (!screen || !screen->isAlive()) return;
uint32_t key = lv_event_get_key(e);
if (key != LV_KEY_BACKSPACE) return;
if (key != LV_KEY_BACKSPACE && key != LV_KEY_ESC) return;
if (lv_obj_t* back_btn = screen->getBackBtn())
{
lv_obj_send_event(back_btn, LV_EVENT_CLICKED, nullptr);
@@ -1158,7 +1158,7 @@ void UiController::key_verify_close_event_cb(lv_event_t* e)
if (code == LV_EVENT_KEY)
{
lv_key_t key = static_cast<lv_key_t>(lv_event_get_key(e));
if (key != LV_KEY_ENTER)
if (key != LV_KEY_ENTER && key != LV_KEY_ESC && key != LV_KEY_BACKSPACE)
{
return;
}
@@ -22,7 +22,16 @@ void request_exit(const ui::placeholder_page::State* state)
void back_event_cb(lv_event_t* event)
{
if (lv_event_get_code(event) != LV_EVENT_CLICKED)
const lv_event_code_t code = lv_event_get_code(event);
if (code == LV_EVENT_KEY)
{
const uint32_t key = lv_event_get_key(event);
if (key != LV_KEY_ESC && key != LV_KEY_BACKSPACE)
{
return;
}
}
else if (code != LV_EVENT_CLICKED)
{
return;
}
@@ -65,6 +74,14 @@ void show(State& state, lv_obj_t* parent)
profile.large_touch_hitbox ? 40 : 32);
lv_obj_align(back_btn, LV_ALIGN_TOP_LEFT, 0, 0);
lv_obj_add_event_cb(back_btn, back_event_cb, LV_EVENT_CLICKED, &state);
lv_obj_add_event_cb(back_btn, back_event_cb, LV_EVENT_KEY, &state);
lv_obj_add_event_cb(state.root, back_event_cb, LV_EVENT_KEY, &state);
if (app_g)
{
lv_group_add_obj(app_g, back_btn);
lv_group_focus_obj(back_btn);
set_default_group(app_g);
}
lv_obj_t* back_label = lv_label_create(back_btn);
const std::string back_text = std::string(LV_SYMBOL_LEFT " ") + ::ui::i18n::tr("Back");
@@ -143,6 +143,7 @@ static void on_del_cancel_clicked(lv_event_t* e);
static void on_discovery_scan_done(lv_timer_t* timer);
static void execute_discovery_command(uint8_t command_index);
static void on_node_info_back_clicked(lv_event_t* e);
static void on_node_info_key(lv_event_t* e);
static void open_chat_compose();
static void close_chat_compose();
static void on_compose_action(chat::ui::ChatComposeScreen::ActionIntent intent, void* user_data);
@@ -1264,11 +1265,13 @@ static void open_node_info_screen_for_node(uint32_t node_id)
lv_group_add_obj(g_contacts_state.node_info_group, widgets.back_btn);
lv_group_focus_obj(widgets.back_btn);
lv_obj_add_event_cb(widgets.back_btn, on_node_info_back_clicked, LV_EVENT_CLICKED, nullptr);
lv_obj_add_event_cb(widgets.back_btn, on_node_info_key, LV_EVENT_KEY, nullptr);
CONTACTS_NODE_INFO_LOG("back button wired and focused back_btn=%p\n", widgets.back_btn);
}
if (widgets.layer_btn)
{
lv_group_add_obj(g_contacts_state.node_info_group, widgets.layer_btn);
lv_obj_add_event_cb(widgets.layer_btn, on_node_info_key, LV_EVENT_KEY, nullptr);
CONTACTS_NODE_INFO_LOG("layer button added layer_btn=%p\n", widgets.layer_btn);
}
@@ -2003,6 +2006,21 @@ static void on_node_info_back_clicked(lv_event_t* /*e*/)
close_node_info_screen();
}
static void on_node_info_key(lv_event_t* e)
{
if (lv_event_get_code(e) != LV_EVENT_KEY)
{
return;
}
const uint32_t key = lv_event_get_key(e);
if (key == LV_KEY_ESC || key == LV_KEY_BACKSPACE)
{
CONTACTS_NODE_INFO_LOG("back key received key=%lu\n", static_cast<unsigned long>(key));
close_node_info_screen();
}
}
static const char* discovery_failure_message(chat::MeshOperationFailure failure,
const char* fallback)
{
@@ -1228,7 +1228,7 @@ void move_cursor_manual(int delta)
void handle_key_common(uint32_t key)
{
if (key == LV_KEY_BACKSPACE)
if (key == LV_KEY_BACKSPACE || key == LV_KEY_ESC)
{
on_back_requested(nullptr);
return;
@@ -114,6 +114,35 @@ void on_back(void*)
request_exit();
}
void show_list_view();
bool is_back_key(uint32_t key)
{
return key == LV_KEY_ESC || key == LV_KEY_BACKSPACE;
}
void on_key(lv_event_t* event)
{
if (lv_event_get_code(event) != LV_EVENT_KEY)
{
return;
}
const uint32_t key = lv_event_get_key(event);
if (!is_back_key(key))
{
return;
}
if (s_runtime.view == MainView::Detail)
{
show_list_view();
}
else
{
request_exit();
}
lv_event_stop_processing(event);
}
void on_focus_scroll(lv_event_t* event)
{
if (lv_event_get_code(event) != LV_EVENT_FOCUSED)
@@ -128,6 +157,17 @@ void on_focus_scroll(lv_event_t* event)
}
}
void add_focusable(lv_obj_t* obj)
{
if (obj == nullptr || app_g == nullptr)
{
return;
}
lv_group_add_obj(app_g, obj);
lv_obj_remove_event_cb(obj, on_key);
lv_obj_add_event_cb(obj, on_key, LV_EVENT_KEY, nullptr);
}
std::string format_size(std::size_t bytes)
{
char buffer[32];
@@ -429,38 +469,38 @@ void sync_focus_group(lv_obj_t* preferred_focus = nullptr)
if (s_runtime.top_bar.back_btn != nullptr)
{
lv_group_add_obj(app_g, s_runtime.top_bar.back_btn);
add_focusable(s_runtime.top_bar.back_btn);
}
if (s_runtime.installed_filter_btn != nullptr)
{
lv_group_add_obj(app_g, s_runtime.installed_filter_btn);
add_focusable(s_runtime.installed_filter_btn);
}
if (s_runtime.uninstalled_filter_btn != nullptr)
{
lv_group_add_obj(app_g, s_runtime.uninstalled_filter_btn);
add_focusable(s_runtime.uninstalled_filter_btn);
}
if (s_runtime.detail_back_btn != nullptr)
{
lv_group_add_obj(app_g, s_runtime.detail_back_btn);
add_focusable(s_runtime.detail_back_btn);
}
for (lv_obj_t* btn : s_runtime.list_buttons)
{
if (btn != nullptr)
{
lv_group_add_obj(app_g, btn);
add_focusable(btn);
}
}
if (s_runtime.primary_action_btn != nullptr)
{
lv_group_add_obj(app_g, s_runtime.primary_action_btn);
add_focusable(s_runtime.primary_action_btn);
}
if (s_runtime.uninstall_btn != nullptr)
{
lv_group_add_obj(app_g, s_runtime.uninstall_btn);
add_focusable(s_runtime.uninstall_btn);
}
if (s_runtime.connect_btn != nullptr)
{
lv_group_add_obj(app_g, s_runtime.connect_btn);
add_focusable(s_runtime.connect_btn);
}
if (preferred_focus != nullptr && lv_obj_is_valid(preferred_focus))
@@ -1025,7 +1025,7 @@ void on_status_toggle_clicked(lv_event_t* e)
void root_key_event_cb(lv_event_t* e)
{
uint32_t key = lv_event_get_key(e);
if (key != LV_KEY_BACKSPACE)
if (key != LV_KEY_BACKSPACE && key != LV_KEY_ESC)
{
return;
}
@@ -1047,7 +1047,7 @@ void root_key_event_cb(lv_event_t* e)
void back_btn_key_event_cb(lv_event_t* e)
{
uint32_t key = lv_event_get_key(e);
if (key != LV_KEY_BACKSPACE)
if (key != LV_KEY_BACKSPACE && key != LV_KEY_ESC)
{
return;
}
@@ -2264,7 +2264,7 @@ void root_key_event_cb(lv_event_t* e)
{
return;
}
if (key == LV_KEY_BACKSPACE)
if (key == LV_KEY_BACKSPACE || key == LV_KEY_ESC)
{
consume_key_event(e);
request_exit();
@@ -136,7 +136,7 @@ void on_back(void*)
void root_key_event_cb(lv_event_t* e)
{
uint32_t key = lv_event_get_key(e);
if (key != LV_KEY_BACKSPACE)
if (key != LV_KEY_BACKSPACE && key != LV_KEY_ESC)
{
return;
}
@@ -1712,6 +1712,31 @@ static void modal_close()
modal_restore_group();
}
static void on_modal_key(lv_event_t* e)
{
if (!e || lv_event_get_code(e) != LV_EVENT_KEY)
{
return;
}
const uint32_t key = lv_event_get_key(e);
if (key == LV_KEY_ESC)
{
modal_close();
lv_event_stop_processing(e);
}
}
static void modal_add_focus_obj(lv_obj_t* obj)
{
if (!obj || !g_state.modal_group)
{
return;
}
lv_group_add_obj(g_state.modal_group, obj);
lv_obj_remove_event_cb(obj, on_modal_key);
lv_obj_add_event_cb(obj, on_modal_key, LV_EVENT_KEY, nullptr);
}
static void on_text_modal_key(lv_event_t* e)
{
if (s_text_modal_ime && s_text_modal_ime->handle_key(e))
@@ -2161,13 +2186,13 @@ static void open_text_modal(const settings::ui::SettingItem& item, settings::ui:
g_state.editing_item = &item;
g_state.editing_widget = &widget;
lv_group_add_obj(g_state.modal_group, g_state.modal_textarea);
modal_add_focus_obj(g_state.modal_textarea);
if (s_text_modal_ime && s_text_modal_ime->focus_obj())
{
lv_group_add_obj(g_state.modal_group, s_text_modal_ime->focus_obj());
modal_add_focus_obj(s_text_modal_ime->focus_obj());
}
lv_group_add_obj(g_state.modal_group, save_btn);
lv_group_add_obj(g_state.modal_group, cancel_btn);
modal_add_focus_obj(save_btn);
modal_add_focus_obj(cancel_btn);
lv_group_focus_obj(g_state.modal_textarea);
}
@@ -2357,11 +2382,11 @@ static void open_manual_datetime_modal(settings::ui::ItemWidget& widget)
{
if (textarea)
{
lv_group_add_obj(g_state.modal_group, textarea);
modal_add_focus_obj(textarea);
}
}
lv_group_add_obj(g_state.modal_group, ok_btn);
lv_group_add_obj(g_state.modal_group, cancel_btn);
modal_add_focus_obj(ok_btn);
modal_add_focus_obj(cancel_btn);
if (s_manual_time_textareas[0])
{
lv_group_focus_obj(s_manual_time_textareas[0]);
@@ -2956,8 +2981,8 @@ static void open_settings_restore_modal()
lv_obj_center(confirm_label);
lv_obj_add_event_cb(confirm_btn, on_settings_restore_confirm_clicked, LV_EVENT_CLICKED, nullptr);
lv_group_add_obj(g_state.modal_group, cancel_btn);
lv_group_add_obj(g_state.modal_group, confirm_btn);
modal_add_focus_obj(cancel_btn);
modal_add_focus_obj(confirm_btn);
lv_group_focus_obj(cancel_btn);
}
@@ -3015,8 +3040,8 @@ static void open_factory_reset_modal()
lv_obj_center(confirm_label);
lv_obj_add_event_cb(confirm_btn, on_factory_reset_confirm_clicked, LV_EVENT_CLICKED, nullptr);
lv_group_add_obj(g_state.modal_group, cancel_btn);
lv_group_add_obj(g_state.modal_group, confirm_btn);
modal_add_focus_obj(cancel_btn);
modal_add_focus_obj(confirm_btn);
lv_group_focus_obj(cancel_btn);
}
@@ -3155,8 +3180,8 @@ static void open_gps_diagnostics_modal()
lv_obj_center(close_label);
lv_obj_add_event_cb(close_btn, on_gps_diagnostics_close_clicked, LV_EVENT_CLICKED, nullptr);
lv_group_add_obj(g_state.modal_group, refresh_btn);
lv_group_add_obj(g_state.modal_group, close_btn);
modal_add_focus_obj(refresh_btn);
modal_add_focus_obj(close_btn);
lv_group_focus_obj(refresh_btn);
}
@@ -3304,7 +3329,7 @@ static void open_enabled_imes_modal(settings::ui::ItemWidget& widget)
{
lv_obj_add_state(btn, LV_STATE_CHECKED);
}
lv_group_add_obj(g_state.modal_group, btn);
modal_add_focus_obj(btn);
++s_ime_toggle_count;
}
@@ -3317,7 +3342,7 @@ static void open_enabled_imes_modal(settings::ui::ItemWidget& widget)
lv_obj_center(back_label);
lv_obj_add_event_cb(back_btn, on_enabled_imes_back_clicked, LV_EVENT_CLICKED, nullptr);
lv_obj_add_event_cb(back_btn, option_modal_focused_cb, LV_EVENT_FOCUSED, nullptr);
lv_group_add_obj(g_state.modal_group, back_btn);
modal_add_focus_obj(back_btn);
if (s_ime_toggle_count > 0)
{
@@ -3405,7 +3430,7 @@ static void open_option_modal(const settings::ui::SettingItem& item, settings::u
lv_obj_add_state(btn, LV_STATE_CHECKED);
}
lv_obj_add_event_cb(btn, option_modal_focused_cb, LV_EVENT_FOCUSED, nullptr);
lv_group_add_obj(g_state.modal_group, btn);
modal_add_focus_obj(btn);
s_option_click_count++;
}
@@ -3419,7 +3444,7 @@ static void open_option_modal(const settings::ui::SettingItem& item, settings::u
lv_obj_center(back_label);
lv_obj_add_event_cb(back_btn, on_option_modal_back_clicked, LV_EVENT_CLICKED, nullptr);
lv_obj_add_event_cb(back_btn, option_modal_focused_cb, LV_EVENT_FOCUSED, nullptr);
lv_group_add_obj(g_state.modal_group, back_btn);
modal_add_focus_obj(back_btn);
if (s_option_click_count > 0)
{
@@ -252,7 +252,7 @@ void on_back(lv_event_t*)
void root_key_event_cb(lv_event_t* e)
{
uint32_t key = lv_event_get_key(e);
if (key != LV_KEY_BACKSPACE)
if (key != LV_KEY_BACKSPACE && key != LV_KEY_ESC)
{
return;
}
@@ -971,6 +971,20 @@ void close_leave_confirm_modal()
modal_restore_group();
}
void leave_confirm_modal_key_cb(lv_event_t* e)
{
if (lv_event_get_code(e) != LV_EVENT_KEY)
{
return;
}
const uint32_t key = lv_event_get_key(e);
if (key == LV_KEY_ESC || key == LV_KEY_BACKSPACE)
{
close_leave_confirm_modal();
lv_event_stop_processing(e);
}
}
uint32_t now_secs()
{
return sys::millis_now() / 1000U;
@@ -984,6 +998,7 @@ lv_obj_t* create_modal_button(lv_obj_t* parent, const char* text, lv_event_cb_t
lv_obj_set_style_pad_hor(btn, kActionBtnPadH, LV_PART_MAIN);
lv_obj_t* label = lv_label_create(btn);
::ui::i18n::set_label_text(label, text);
lv_obj_add_event_cb(btn, leave_confirm_modal_key_cb, LV_EVENT_KEY, nullptr);
lv_obj_update_layout(label);
lv_coord_t width = lv_obj_get_width(label) + (kActionBtnPadH * 2);
if (width < ::ui::page_profile::resolve_compact_button_min_width())
@@ -24,7 +24,7 @@ lv_obj_t* back_button()
void root_key_event_cb(lv_event_t* e)
{
uint32_t key = lv_event_get_key(e);
if (key != LV_KEY_BACKSPACE)
if (key != LV_KEY_BACKSPACE && key != LV_KEY_ESC)
{
return;
}
@@ -152,7 +152,7 @@ void on_backspace_key(lv_event_t* e)
return;
}
uint32_t key = lv_event_get_key(e);
if (key != LV_KEY_BACKSPACE)
if (key != LV_KEY_BACKSPACE && key != LV_KEY_ESC)
{
return;
}
@@ -165,7 +165,7 @@ void back_event_handler(void* user_data)
void root_key_event_cb(lv_event_t* e)
{
const uint32_t key = lv_event_get_key(e);
if (key == LV_KEY_BACKSPACE)
if (key == LV_KEY_BACKSPACE || key == LV_KEY_ESC)
{
begin_exit();
}
@@ -139,7 +139,7 @@ void on_back(void*)
void root_key_event_cb(lv_event_t* e)
{
uint32_t key = lv_event_get_key(e);
if (key != LV_KEY_BACKSPACE)
if (key != LV_KEY_BACKSPACE && key != LV_KEY_ESC)
{
return;
}
@@ -172,7 +172,7 @@ void monitor_row_event_cb(lv_event_t* e)
lv_event_stop_processing(e);
return;
}
if (key == LV_KEY_BACKSPACE)
if (key == LV_KEY_BACKSPACE || key == LV_KEY_ESC)
{
on_back(nullptr);
lv_event_stop_processing(e);