cellOsk: partially implement continuous mode

This commit is contained in:
Megamouse 2021-09-21 00:59:11 +02:00
parent e3ec71c683
commit a7cb513a89
3 changed files with 74 additions and 39 deletions

View file

@ -33,6 +33,23 @@ void fmt_class_string<CellOskDialogError>::format(std::string& out, u64 arg)
}); });
} }
template<>
void fmt_class_string<CellOskDialogContinuousMode>::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() OskDialogBase::~OskDialogBase()
{ {
} }
@ -154,7 +171,7 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
auto osk = _get_osk_dialog(true); auto osk = _get_osk_dialog(true);
// Can't open another dialog if this one is already open. // 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; return CELL_SYSUTIL_ERROR_BUSY;
} }
@ -200,21 +217,10 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
osk->on_osk_close = [wptr = std::weak_ptr<OskDialogBase>(osk)](s32 status) osk->on_osk_close = [wptr = std::weak_ptr<OskDialogBase>(osk)](s32 status)
{ {
cellOskDialog.error("on_osk_close(status=%d)", status);
const auto osk = wptr.lock(); const auto osk = wptr.lock();
osk->state = OskDialogState::Closed;
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");
}
auto& info = g_fxo->get<osk_info>(); auto& info = g_fxo->get<osk_info>();
@ -275,11 +281,16 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED; osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED;
break; break;
} }
default: case FAKE_CELL_OSKDIALOG_CLOSE_ABORT:
{ {
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT; osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT;
break; break;
} }
default:
{
cellOskDialog.fatal("on_osk_close: Unknown status (%d)", status);
break;
}
} }
// Send OSK status // Send OSK status
@ -299,15 +310,24 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0); sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0);
break; break;
} }
case FAKE_CELL_OSKDIALOG_CLOSE_ABORT:
{
// Handled in cellOskDialogAbort
break;
}
default: default:
{ {
info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_FINISHED; cellOskDialog.fatal("on_osk_close: Unknown status (%d)", status);
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
break; 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; info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_FINISHED;
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0); sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
@ -316,6 +336,13 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
input::SetIntercepted(false); input::SetIntercepted(false);
}; };
if (auto& info = g_fxo->get<osk_info>(); 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); input::SetIntercepted(true);
Emu.CallAfter([=, &result]() Emu.CallAfter([=, &result]()
@ -323,12 +350,14 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
osk->Create(get_localized_string(localized_string_id::CELL_OSK_DIALOG_TITLE), message, osk->osk_text, maxLength, prohibitFlgs, allowOskPanelFlg, firstViewPanel); osk->Create(get_localized_string(localized_string_id::CELL_OSK_DIALOG_TITLE), message, osk->osk_text, maxLength, prohibitFlgs, allowOskPanelFlg, firstViewPanel);
result = true; result = true;
result.notify_one(); result.notify_one();
if (g_fxo->get<osk_info>().osk_continuous_mode.load() == CELL_OSKDIALOG_CONTINUOUS_MODE_HIDE)
{
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_DISPLAY_CHANGED, CELL_OSKDIALOG_DISPLAY_STATUS_SHOW);
}
}); });
{ g_fxo->get<osk_info>().last_dialog_state = CELL_SYSUTIL_OSKDIALOG_LOADED;
auto& info = g_fxo->get<osk_info>();
info.last_dialog_state = CELL_SYSUTIL_OSKDIALOG_LOADED;
}
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0); sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0);
while (!result && !Emu.IsStopped()) while (!result && !Emu.IsStopped())
@ -420,6 +449,7 @@ error_code getText(vm::ptr<CellOskDialogCallbackReturnParam> OutputInfo, bool is
info.reset(); info.reset();
} }
osk->state = OskDialogState::Unloaded;
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_UNLOADED, 0); sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_UNLOADED, 0);
} }
else if (keep_seperate_window_open) else if (keep_seperate_window_open)
@ -483,18 +513,12 @@ error_code cellOskDialogAbort()
const s32 result = osk->state.atomic_op([](OskDialogState& state) 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. // Check for open dialog. In this case the dialog is "Open" if it was not unloaded before.
if (state == OskDialogState::Abort) if (state == OskDialogState::Unloaded)
{ {
return static_cast<s32>(CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED); return static_cast<s32>(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<s32>(CELL_SYSUTIL_ERROR_BUSY);
}
state = OskDialogState::Abort; state = OskDialogState::Abort;
return static_cast<s32>(CELL_OK); return static_cast<s32>(CELL_OK);
@ -506,7 +530,10 @@ error_code cellOskDialogAbort()
} }
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT; osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT;
osk->Close(-1); osk->Close(FAKE_CELL_OSKDIALOG_CLOSE_ABORT);
g_fxo->get<osk_info>().last_dialog_state = CELL_SYSUTIL_OSKDIALOG_FINISHED;
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
return CELL_OK; return CELL_OK;
} }
@ -536,7 +563,9 @@ error_code cellOskDialogSetSeparateWindowOption(vm::ptr<CellOskDialogSeparateWin
auto& osk = g_fxo->get<osk_info>(); auto& osk = g_fxo->get<osk_info>();
osk.use_separate_windows = true; osk.use_separate_windows = true;
osk.osk_continuous_mode = static_cast<CellOskDialogContinuousMode>(+windowOption->continuousMode); osk.osk_continuous_mode = static_cast<CellOskDialogContinuousMode>(+windowOption->continuousMode);
// TODO: rest // TODO: handle rest of windowOption
cellOskDialog.warning("cellOskDialogSetSeparateWindowOption: continuousMode=%s)", osk.osk_continuous_mode.load());
return CELL_OK; return CELL_OK;
} }
@ -702,8 +731,8 @@ error_code cellOskDialogExtSendFinishMessage(u32 /*CellOskDialogFinishReason*/ f
const auto osk = _get_osk_dialog(); const auto osk = _get_osk_dialog();
// Check for open dialog. // Check for "Open" dialog.
if (!osk || osk->state.load() != OskDialogState::Open) if (!osk || osk->state.load() == OskDialogState::Unloaded)
{ {
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED; return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
} }

View file

@ -83,6 +83,11 @@ enum CellOskDialogFinishReason
CELL_OSKDIALOG_CLOSE_CANCEL = 1, CELL_OSKDIALOG_CLOSE_CANCEL = 1,
}; };
enum CellOskDialogFinishReasonFake // Helper. Must be negative values.
{
FAKE_CELL_OSKDIALOG_CLOSE_ABORT = -1,
};
enum CellOskDialogType enum CellOskDialogType
{ {
CELL_OSKDIALOG_TYPE_SINGLELINE_OSK = 0, CELL_OSKDIALOG_TYPE_SINGLELINE_OSK = 0,
@ -239,9 +244,10 @@ using cellOskDialogForceFinishCallback = class b8();
enum class OskDialogState enum class OskDialogState
{ {
Unloaded,
Open, Open,
Abort, Abort,
Close, Closed
}; };
class OskDialogBase class OskDialogBase
@ -258,7 +264,7 @@ public:
std::function<void(s32 status)> on_osk_close; std::function<void(s32 status)> on_osk_close;
std::function<void()> on_osk_input_entered; std::function<void()> on_osk_input_entered;
atomic_t<OskDialogState> state{ OskDialogState::Close }; atomic_t<OskDialogState> state{ OskDialogState::Unloaded };
atomic_t<CellOskDialogInputFieldResult> osk_input_result{ CellOskDialogInputFieldResult::CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK }; atomic_t<CellOskDialogInputFieldResult> osk_input_result{ CellOskDialogInputFieldResult::CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK };
char16_t osk_text[CELL_OSKDIALOG_STRING_SIZE]{}; char16_t osk_text[CELL_OSKDIALOG_STRING_SIZE]{};

View file

@ -170,7 +170,7 @@ void osk_dialog_frame::Create(const std::string& title, const std::u16string& me
on_osk_close(CELL_OSKDIALOG_CLOSE_CANCEL); on_osk_close(CELL_OSKDIALOG_CLOSE_CANCEL);
break; break;
default: default:
on_osk_close(-1); on_osk_close(result);
break; break;
} }
}); });
@ -198,7 +198,7 @@ void osk_dialog_frame::Close(s32 status)
m_dialog->done(QDialog::Rejected); m_dialog->done(QDialog::Rejected);
break; break;
default: default:
m_dialog->done(-1); m_dialog->done(status);
break; break;
} }
} }