diff --git a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp index 3810d4480b..48851c8a41 100644 --- a/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp +++ b/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp @@ -33,6 +33,23 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +template<> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](auto mode) + { + switch (mode) + { + STR_CASE(CELL_OSKDIALOG_CONTINUOUS_MODE_NONE); + STR_CASE(CELL_OSKDIALOG_CONTINUOUS_MODE_REMAIN_OPEN); + STR_CASE(CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE); + STR_CASE(CELL_OSKDIALOG_CONTINUOUS_MODE_SHOW); + } + + return unknown; + }); +} + OskDialogBase::~OskDialogBase() { } @@ -154,7 +171,7 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia auto osk = _get_osk_dialog(true); // Can't open another dialog if this one is already open. - if (!osk || osk->state.load() == OskDialogState::Open) + if (!osk || osk->state.load() != OskDialogState::Unloaded) { return CELL_SYSUTIL_ERROR_BUSY; } @@ -200,21 +217,10 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia osk->on_osk_close = [wptr = std::weak_ptr(osk)](s32 status) { + cellOskDialog.error("on_osk_close(status=%d)", status); + const auto osk = wptr.lock(); - - if (osk->state.atomic_op([&](OskDialogState& state) - { - if (state == OskDialogState::Abort) - { - return true; - } - - state = OskDialogState::Close; - return false; - })) - { - cellOskDialog.notice("Called on_osk_close after abort"); - } + osk->state = OskDialogState::Closed; auto& info = g_fxo->get(); @@ -275,11 +281,16 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED; break; } - default: + case FAKE_CELL_OSKDIALOG_CLOSE_ABORT: { osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT; break; } + default: + { + cellOskDialog.fatal("on_osk_close: Unknown status (%d)", status); + break; + } } // Send OSK status @@ -299,15 +310,24 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0); break; } + case FAKE_CELL_OSKDIALOG_CLOSE_ABORT: + { + // Handled in cellOskDialogAbort + break; + } default: { - info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_FINISHED; - sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0); + cellOskDialog.fatal("on_osk_close: Unknown status (%d)", status); break; } } + + if (info.osk_continuous_mode.load() == CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE) + { + sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_DISPLAY_CHANGED, CELL_OSKDIALOG_DISPLAY_STATUS_HIDE); + } } - else + else if (status != FAKE_CELL_OSKDIALOG_CLOSE_ABORT) // Handled in cellOskDialogAbort { info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_FINISHED; sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0); @@ -316,6 +336,13 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia input::SetIntercepted(false); }; + if (auto& info = g_fxo->get(); info.osk_continuous_mode == CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE) + { + info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_LOADED; + sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0); + return CELL_OK; + } + input::SetIntercepted(true); Emu.CallAfter([=, &result]() @@ -323,12 +350,14 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr dia osk->Create(get_localized_string(localized_string_id::CELL_OSK_DIALOG_TITLE), message, osk->osk_text, maxLength, prohibitFlgs, allowOskPanelFlg, firstViewPanel); result = true; result.notify_one(); + + if (g_fxo->get().osk_continuous_mode.load() == CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE) + { + sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_DISPLAY_CHANGED, CELL_OSKDIALOG_DISPLAY_STATUS_SHOW); + } }); - { - auto& info = g_fxo->get(); - info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_LOADED; - } + g_fxo->get().last_dialog_state = CELL_SYSUTIL_OSKDIALOG_LOADED; sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0); while (!result && !Emu.IsStopped()) @@ -420,6 +449,7 @@ error_code getText(vm::ptr OutputInfo, bool is info.reset(); } + osk->state = OskDialogState::Unloaded; sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_UNLOADED, 0); } else if (keep_seperate_window_open) @@ -483,18 +513,12 @@ error_code cellOskDialogAbort() const s32 result = osk->state.atomic_op([](OskDialogState& state) { - // Check for open dialog. In this case the dialog is only "Open" if it was not aborted before. - if (state == OskDialogState::Abort) + // Check for open dialog. In this case the dialog is "Open" if it was not unloaded before. + if (state == OskDialogState::Unloaded) { return static_cast(CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED); } - // If the dialog has the Open state then it is in use. Only dialogs with the Close state can be aborted. - if (state == OskDialogState::Open) - { - return static_cast(CELL_SYSUTIL_ERROR_BUSY); - } - state = OskDialogState::Abort; return static_cast(CELL_OK); @@ -506,7 +530,10 @@ error_code cellOskDialogAbort() } osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT; - osk->Close(-1); + osk->Close(FAKE_CELL_OSKDIALOG_CLOSE_ABORT); + + g_fxo->get().last_dialog_state = CELL_SYSUTIL_OSKDIALOG_FINISHED; + sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0); return CELL_OK; } @@ -536,7 +563,9 @@ error_code cellOskDialogSetSeparateWindowOption(vm::ptrget(); osk.use_separate_windows = true; osk.osk_continuous_mode = static_cast(+windowOption->continuousMode); - // TODO: rest + // TODO: handle rest of windowOption + + cellOskDialog.warning("cellOskDialogSetSeparateWindowOption: continuousMode=%s)", osk.osk_continuous_mode.load()); return CELL_OK; } @@ -702,8 +731,8 @@ error_code cellOskDialogExtSendFinishMessage(u32 /*CellOskDialogFinishReason*/ f const auto osk = _get_osk_dialog(); - // Check for open dialog. - if (!osk || osk->state.load() != OskDialogState::Open) + // Check for "Open" dialog. + if (!osk || osk->state.load() == OskDialogState::Unloaded) { return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED; } diff --git a/rpcs3/Emu/Cell/Modules/cellOskDialog.h b/rpcs3/Emu/Cell/Modules/cellOskDialog.h index 83f9203418..b363de22f9 100644 --- a/rpcs3/Emu/Cell/Modules/cellOskDialog.h +++ b/rpcs3/Emu/Cell/Modules/cellOskDialog.h @@ -83,6 +83,11 @@ enum CellOskDialogFinishReason CELL_OSKDIALOG_CLOSE_CANCEL = 1, }; +enum CellOskDialogFinishReasonFake // Helper. Must be negative values. +{ + FAKE_CELL_OSKDIALOG_CLOSE_ABORT = -1, +}; + enum CellOskDialogType { CELL_OSKDIALOG_TYPE_SINGLELINE_OSK = 0, @@ -239,9 +244,10 @@ using cellOskDialogForceFinishCallback = class b8(); enum class OskDialogState { + Unloaded, Open, Abort, - Close, + Closed }; class OskDialogBase @@ -258,7 +264,7 @@ public: std::function on_osk_close; std::function on_osk_input_entered; - atomic_t state{ OskDialogState::Close }; + atomic_t state{ OskDialogState::Unloaded }; atomic_t osk_input_result{ CellOskDialogInputFieldResult::CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK }; char16_t osk_text[CELL_OSKDIALOG_STRING_SIZE]{}; diff --git a/rpcs3/rpcs3qt/osk_dialog_frame.cpp b/rpcs3/rpcs3qt/osk_dialog_frame.cpp index df145bddbc..4e33316c9a 100644 --- a/rpcs3/rpcs3qt/osk_dialog_frame.cpp +++ b/rpcs3/rpcs3qt/osk_dialog_frame.cpp @@ -170,7 +170,7 @@ void osk_dialog_frame::Create(const std::string& title, const std::u16string& me on_osk_close(CELL_OSKDIALOG_CLOSE_CANCEL); break; default: - on_osk_close(-1); + on_osk_close(result); break; } }); @@ -198,7 +198,7 @@ void osk_dialog_frame::Close(s32 status) m_dialog->done(QDialog::Rejected); break; default: - m_dialog->done(-1); + m_dialog->done(status); break; } }