overlay: fix input related bugs

This commit is contained in:
KorewaWatchful
2026-05-20 11:12:40 -04:00
committed by Gamid
parent 0517f5f5fb
commit b52c735f39
12 changed files with 160 additions and 121 deletions
+2 -2
View File
@@ -577,6 +577,7 @@ void apply_renderer_config(EmuEnvState &emuenv) {
r.common_dialog = &emuenv.common_dialog;
r.sys_date_format = cc.sys_date_format;
r.sys_lang = cc.sys_lang;
r.sys_button = cc.sys_button;
r.show_compile_shaders = emuenv.cfg.show_compile_shaders;
app::sync_perf_overlay_config(emuenv);
@@ -592,8 +593,6 @@ void apply_renderer_config(EmuEnvState &emuenv) {
ctrl.overlay_input_intercepted.store(true, std::memory_order_relaxed);
} else {
ctrl.overlay_input_intercepted.store(false, std::memory_order_relaxed);
std::lock_guard<std::mutex> lock(ctrl.mutex);
ctrl.ignore_input = true;
}
},
[&emuenv]() -> overlay::overlay_touch_state {
@@ -662,6 +661,7 @@ void apply_runtime_settings(EmuEnvState &emuenv) {
emuenv.display.fps_hack = cc.fps_hack;
r.sys_date_format = cc.sys_date_format;
r.sys_lang = cc.sys_lang;
r.sys_button = cc.sys_button;
r.show_compile_shaders = emuenv.cfg.show_compile_shaders;
app::sync_perf_overlay_config(emuenv);
}
-4
View File
@@ -248,10 +248,6 @@ void AppSessionController::apply_runtime_state_locked() {
const bool overlay_intercepted = paused || input_intercepted;
emuenv.ctrl.overlay_input_intercepted.store(overlay_intercepted, std::memory_order_relaxed);
if (overlay_intercepted || currently_paused != paused) {
std::lock_guard<std::mutex> ctrl_lock(emuenv.ctrl.mutex);
emuenv.ctrl.ignore_input = true;
}
emuenv.renderer->paused.store(paused, std::memory_order_relaxed);
}
-2
View File
@@ -76,7 +76,6 @@ struct CtrlState {
VirtualKeyboardState keyboard_state;
std::atomic<bool> overlay_input_intercepted{ false };
bool ignore_input = false;
struct OverlayMouseState {
std::atomic<float> x{ 0.f };
@@ -95,7 +94,6 @@ struct CtrlState {
std::fill_n(last_vcount, 5, 0);
keyboard_state = {};
overlay_input_intercepted.store(false, std::memory_order_relaxed);
ignore_input = false;
overlay_mouse.x.store(0.f, std::memory_order_relaxed);
overlay_mouse.y.store(0.f, std::memory_order_relaxed);
overlay_mouse.pressed.store(false, std::memory_order_relaxed);
-12
View File
@@ -278,18 +278,6 @@ static void retrieve_ctrl_data(EmuEnvState &emuenv, int port, bool is_v2, bool n
}
}
if (state.ignore_input) {
constexpr uint32_t face_mask = SCE_CTRL_CROSS | SCE_CTRL_CIRCLE | SCE_CTRL_TRIANGLE
| SCE_CTRL_SQUARE | SCE_CTRL_START | SCE_CTRL_SELECT;
if (buttons & face_mask) {
buttons = 0;
axes.fill(0);
reset_axes();
return;
}
state.ignore_input = false;
}
reset_axes();
}
@@ -41,6 +41,20 @@
#include <util/tracy.h>
TRACY_MODULE_NAME(SceCommonDialog);
namespace {
void complete_trophy_setup_dialog(DialogState &dialog) {
std::lock_guard<std::recursive_mutex> lock(dialog.mutex);
if (dialog.type != TROPHY_SETUP_DIALOG || dialog.status != SCE_COMMON_DIALOG_STATUS_RUNNING)
return;
if (SDL_GetTicks() < dialog.trophy.tick)
return;
dialog.status = SCE_COMMON_DIALOG_STATUS_FINISHED;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
}
} // namespace
template <>
std::string to_debug_str<SceMsgDialogProgressBarTarget>(const MemState &mem, SceMsgDialogProgressBarTarget type) {
switch (type) {
@@ -740,6 +754,7 @@ EXPORT(int, sceNpTrophySetupDialogAbort) {
EXPORT(int, sceNpTrophySetupDialogGetResult, Ptr<SceNpTrophySetupDialogResult> result) {
TRACY_FUNC(sceNpTrophySetupDialogGetResult, result);
complete_trophy_setup_dialog(emuenv.common_dialog);
if (emuenv.common_dialog.type != TROPHY_SETUP_DIALOG || emuenv.common_dialog.status != SCE_COMMON_DIALOG_STATUS_FINISHED)
return RET_ERROR(SCE_COMMON_DIALOG_ERROR_NOT_FINISHED);
@@ -749,6 +764,7 @@ EXPORT(int, sceNpTrophySetupDialogGetResult, Ptr<SceNpTrophySetupDialogResult> r
EXPORT(int, sceNpTrophySetupDialogGetStatus) {
TRACY_FUNC(sceNpTrophySetupDialogGetStatus);
complete_trophy_setup_dialog(emuenv.common_dialog);
return emuenv.common_dialog.status;
}
@@ -765,6 +781,7 @@ EXPORT(int, sceNpTrophySetupDialogInit, const Ptr<SceNpTrophySetupDialogParam> p
EXPORT(int, sceNpTrophySetupDialogTerm) {
TRACY_FUNC(sceNpTrophySetupDialogTerm);
complete_trophy_setup_dialog(emuenv.common_dialog);
if (emuenv.common_dialog.type != TROPHY_SETUP_DIALOG)
return RET_ERROR(SCE_COMMON_DIALOG_ERROR_NOT_IN_USE);
@@ -41,7 +41,7 @@ public:
void on_button_pressed(pad_button button_press, bool is_auto_repeat) override;
void on_touch_pressed(float vx, float vy) override;
bool poll_dialog(DialogState &dialog, int date_format);
bool poll_dialog(DialogState &dialog, int date_format, int sys_button);
private:
int m_active_type = 0;
@@ -169,6 +169,10 @@ private:
DialogState *m_dialog = nullptr;
int m_date_format = 0;
int m_sys_button = 0;
bool is_confirm_button(pad_button button) const;
bool is_cancel_button(pad_button button) const;
static constexpr uint16_t k_vw = 960;
static constexpr uint16_t k_vh = 544;
@@ -88,6 +88,7 @@ public:
m_stop_input_loop.store(false);
m_stop_pad_interception.store(false);
}
void stop_input_processing(bool stop_pad_interception);
compiled_resource get_compiled() override = 0;
+116 -87
View File
@@ -173,9 +173,10 @@ std::string common_dialog_overlay::format_date_time(int date_format, const void
return date_str + fmt::format(" {}:{:02d}", dt->hour, dt->minute);
}
bool common_dialog_overlay::poll_dialog(DialogState &dialog, int date_format) {
bool common_dialog_overlay::poll_dialog(DialogState &dialog, int date_format, int sys_button) {
m_dialog = &dialog;
m_date_format = date_format;
m_sys_button = sys_button;
std::lock_guard<std::recursive_mutex> lock(dialog.mutex);
@@ -415,6 +416,18 @@ bool common_dialog_overlay::poll_dialog(DialogState &dialog, int date_format) {
return true;
}
bool common_dialog_overlay::is_confirm_button(pad_button button) const {
if (m_sys_button == SCE_SYSTEM_PARAM_ENTER_BUTTON_CIRCLE)
return button == pad_button::circle;
return button == pad_button::cross;
}
bool common_dialog_overlay::is_cancel_button(pad_button button) const {
if (m_sys_button == SCE_SYSTEM_PARAM_ENTER_BUTTON_CIRCLE)
return button == pad_button::cross;
return button == pad_button::circle;
}
void common_dialog_overlay::update(uint64_t timestamp_us) {
if (m_fade_anim.active)
m_fade_anim.update(timestamp_us);
@@ -1519,6 +1532,27 @@ void common_dialog_overlay::handle_message_input(pad_button btn, DialogState &di
if (m_buttons.empty())
return;
if (is_confirm_button(btn)) {
const auto &selected = m_buttons[m_selected_button];
dialog.msg.status = selected.value;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
dialog.status = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
return;
}
if (is_cancel_button(btn)) {
if (m_buttons.size() > 1) {
dialog.msg.status = m_buttons.back().value;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
dialog.status = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
}
return;
}
switch (btn) {
case pad_button::dpad_left:
case pad_button::ls_left:
@@ -1530,30 +1564,45 @@ void common_dialog_overlay::handle_message_input(pad_button btn, DialogState &di
if (m_selected_button < static_cast<int>(m_buttons.size()) - 1)
m_selected_button++;
break;
case pad_button::cross: {
const auto &selected = m_buttons[m_selected_button];
dialog.msg.status = selected.value;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
dialog.status = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
break;
}
case pad_button::circle:
if (m_buttons.size() > 1) {
dialog.msg.status = m_buttons.back().value;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
dialog.status = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
}
break;
default:
break;
}
}
void common_dialog_overlay::handle_savedata_list_input(pad_button btn, DialogState &dialog) {
if (is_confirm_button(btn)) {
if (m_cancel_btn_focused) {
dialog.savedata.button_id = SCE_SAVEDATA_DIALOG_BUTTON_ID_INVALID;
dialog.savedata.draw_info_window = false;
dialog.result = SCE_COMMON_DIALOG_RESULT_USER_CANCELED;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
return;
}
if (!m_save_slots.empty()) {
const uint32_t slot_index = m_save_slots[m_selected_slot]->slot_index;
dialog.savedata.selected_save = slot_index;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
dialog.savedata.mode_to_display = SCE_SAVEDATA_DIALOG_MODE_FIXED;
}
return;
}
if (is_cancel_button(btn)) {
dialog.savedata.button_id = SCE_SAVEDATA_DIALOG_BUTTON_ID_INVALID;
dialog.savedata.draw_info_window = false;
dialog.result = SCE_COMMON_DIALOG_RESULT_USER_CANCELED;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
return;
}
switch (btn) {
case pad_button::dpad_up:
case pad_button::ls_up:
@@ -1580,40 +1629,12 @@ void common_dialog_overlay::handle_savedata_list_input(pad_button btn, DialogSta
m_scroll_offset = m_selected_slot - k_max_visible_slots + 1;
}
break;
case pad_button::cross:
if (m_cancel_btn_focused) {
dialog.savedata.button_id = SCE_SAVEDATA_DIALOG_BUTTON_ID_INVALID;
dialog.savedata.draw_info_window = false;
dialog.result = SCE_COMMON_DIALOG_RESULT_USER_CANCELED;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
break;
}
if (!m_save_slots.empty()) {
const uint32_t slot_index = m_save_slots[m_selected_slot]->slot_index;
dialog.savedata.selected_save = slot_index;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
dialog.savedata.mode_to_display = SCE_SAVEDATA_DIALOG_MODE_FIXED;
}
break;
case pad_button::triangle:
if (!m_cancel_btn_focused && !m_save_slots.empty() && m_save_slots[m_selected_slot]->has_data) {
dialog.savedata.draw_info_window = true;
dialog.savedata.selected_save = m_save_slots[m_selected_slot]->slot_index;
}
break;
case pad_button::circle:
dialog.savedata.button_id = SCE_SAVEDATA_DIALOG_BUTTON_ID_INVALID;
dialog.savedata.draw_info_window = false;
dialog.result = SCE_COMMON_DIALOG_RESULT_USER_CANCELED;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
break;
default:
break;
}
@@ -1623,6 +1644,25 @@ void common_dialog_overlay::handle_savedata_fixed_input(pad_button btn, DialogSt
if (m_buttons.empty())
return;
if (is_confirm_button(btn)) {
const auto &selected = m_buttons[m_selected_button];
dialog.savedata.button_id = selected.value;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
return;
}
if (is_cancel_button(btn)) {
dialog.savedata.button_id = SCE_SAVEDATA_DIALOG_BUTTON_ID_INVALID;
dialog.result = SCE_COMMON_DIALOG_RESULT_USER_CANCELED;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
return;
}
switch (btn) {
case pad_button::dpad_left:
case pad_button::ls_left:
@@ -1634,22 +1674,6 @@ void common_dialog_overlay::handle_savedata_fixed_input(pad_button btn, DialogSt
if (m_selected_button < static_cast<int>(m_buttons.size()) - 1)
m_selected_button++;
break;
case pad_button::cross: {
const auto &selected = m_buttons[m_selected_button];
dialog.savedata.button_id = selected.value;
dialog.result = SCE_COMMON_DIALOG_RESULT_OK;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
break;
}
case pad_button::circle:
dialog.savedata.button_id = SCE_SAVEDATA_DIALOG_BUTTON_ID_INVALID;
dialog.result = SCE_COMMON_DIALOG_RESULT_USER_CANCELED;
dialog.substatus = SCE_COMMON_DIALOG_STATUS_FINISHED;
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
break;
default:
break;
}
@@ -1667,6 +1691,28 @@ void common_dialog_overlay::handle_savedata_info_input(pad_button btn, DialogSta
}
void common_dialog_overlay::handle_ime_input(pad_button btn, DialogState &dialog) {
if (is_confirm_button(btn)) {
if (m_selected_button == 0) {
submit_ime_dialog(dialog);
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
} else {
cancel_ime_dialog(dialog);
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
}
return;
}
if (is_cancel_button(btn)) {
if (m_ime_cancelable) {
cancel_ime_dialog(dialog);
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
}
return;
}
switch (btn) {
case pad_button::dpad_left:
case pad_button::ls_left:
@@ -1678,25 +1724,6 @@ void common_dialog_overlay::handle_ime_input(pad_button btn, DialogState &dialog
if (m_selected_button < static_cast<int>(m_buttons.size()) - 1)
m_selected_button++;
break;
case pad_button::cross: {
if (m_selected_button == 0) {
submit_ime_dialog(dialog);
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
} else {
cancel_ime_dialog(dialog);
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
}
break;
}
case pad_button::circle:
if (m_ime_cancelable) {
cancel_ime_dialog(dialog);
m_stop_input_loop.store(true);
m_stop_pad_interception.store(true);
}
break;
default:
break;
}
@@ -1707,6 +1734,8 @@ void common_dialog_overlay::on_touch_pressed(float vx, float vy) {
return;
std::lock_guard<std::recursive_mutex> lock(m_dialog->mutex);
const auto confirm_button = (m_sys_button == SCE_SYSTEM_PARAM_ENTER_BUTTON_CIRCLE) ? pad_button::circle : pad_button::cross;
const auto cancel_button = (m_sys_button == SCE_SYSTEM_PARAM_ENTER_BUTTON_CIRCLE) ? pad_button::cross : pad_button::circle;
switch (m_active_type) {
case MESSAGE_DIALOG:
@@ -1716,7 +1745,7 @@ void common_dialog_overlay::on_touch_pressed(float vx, float vy) {
if (vx >= btn.bg.x && vx <= btn.bg.x + btn.bg.w
&& vy >= btn.bg.y && vy <= btn.bg.y + btn.bg.h) {
m_selected_button = static_cast<int>(i);
on_button_pressed(pad_button::cross, false);
on_button_pressed(confirm_button, false);
return;
}
}
@@ -1724,7 +1753,7 @@ void common_dialog_overlay::on_touch_pressed(float vx, float vy) {
}
case SAVEDATA_DIALOG: {
if (m_savedata_info_mode) {
on_button_pressed(pad_button::circle, false);
on_button_pressed(cancel_button, false);
return;
}
if (m_savedata_list_mode) {
@@ -1732,7 +1761,7 @@ void common_dialog_overlay::on_touch_pressed(float vx, float vy) {
const uint16_t cancel_w = 46, cancel_h = 46;
if (vx >= cancel_x && vx <= cancel_x + cancel_w
&& vy >= cancel_y && vy <= cancel_y + cancel_h) {
on_button_pressed(pad_button::circle, false);
on_button_pressed(cancel_button, false);
return;
}
const int16_t list_start_y = 96;
@@ -1759,7 +1788,7 @@ void common_dialog_overlay::on_touch_pressed(float vx, float vy) {
m_selected_slot = i;
m_cancel_btn_focused = false;
on_button_pressed(pad_button::cross, false);
on_button_pressed(confirm_button, false);
return;
}
}
@@ -1769,7 +1798,7 @@ void common_dialog_overlay::on_touch_pressed(float vx, float vy) {
if (vx >= btn.bg.x && vx <= btn.bg.x + btn.bg.w
&& vy >= btn.bg.y && vy <= btn.bg.y + btn.bg.h) {
m_selected_button = static_cast<int>(i);
on_button_pressed(pad_button::cross, false);
on_button_pressed(confirm_button, false);
return;
}
}
+1
View File
@@ -174,6 +174,7 @@ void display_manager::on_overlay_removed(const std::shared_ptr<overlay> &item) {
return;
}
iface->stop_input_processing(true);
iface->detach_input();
}
+16 -12
View File
@@ -148,31 +148,35 @@ int32_t user_interface::run_input_loop(overlay_input_handler *input, std::functi
input->set_intercepted(false);
}
m_interactive.store(false);
m_input_loop_exited.store(true);
m_input_loop_exited.notify_all();
return result;
}
void user_interface::close(bool use_callback, bool stop_pad_interception) {
void user_interface::stop_input_processing(bool stop_pad_interception) {
m_stop_pad_interception.store(stop_pad_interception);
m_stop_input_loop.store(true);
const bool interactive = m_interactive.load();
const bool same_thread = interactive && std::this_thread::get_id() == m_input_loop_thread_id;
if (interactive && !same_thread) {
m_input_loop_exited.wait(false);
}
if (stop_pad_interception && release_intercept && (!same_thread) && !m_interactive.load()) {
release_intercept();
}
}
void user_interface::close(bool use_callback, bool stop_pad_interception) {
stop_input_processing(stop_pad_interception);
// If the input loop is running on a different thread, wait for it to fully
// exit before firing callbacks. When close() is called from within
// on_button_pressed (same thread as run_input_loop), the loop will exit
// naturally after the callback returns — no wait needed.
if (m_interactive.load() && std::this_thread::get_id() != m_input_loop_thread_id) {
m_input_loop_exited.wait(false);
}
// Only disable pad interception if this user interface is not interactive.
// Interactive user interfaces handle this in run_input_loop in order to
// prevent potential mutex issues.
if (!m_interactive.load() && m_stop_pad_interception.load() && release_intercept) {
release_intercept();
}
if (on_close && use_callback) {
on_close(return_code);
}
+1
View File
@@ -183,6 +183,7 @@ struct State {
DialogState *common_dialog = nullptr;
int sys_date_format = 0;
int sys_lang = 0;
int sys_button = 0;
PerformanceOverlayState perf_overlay;
+1 -1
View File
@@ -97,7 +97,7 @@ void State::update_overlays() {
dlg = overlay_manager->create<overlay::common_dialog_overlay>();
just_created = true;
}
if (dlg->poll_dialog(*common_dialog, sys_date_format)
if (dlg->poll_dialog(*common_dialog, sys_date_format, sys_button)
&& common_dialog->type != TROPHY_SETUP_DIALOG) {
if (just_created || dlg->input_loop_exited()) {
dlg->reset_input_loop();