cellOskDialog: add multi-line option and handle more permutations (WIP)

This commit is contained in:
Megamouse 2019-01-05 18:11:43 +01:00
parent 4a8b30c625
commit 17058113df
4 changed files with 156 additions and 49 deletions

View file

@ -35,7 +35,7 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
{
cellOskDialog.warning("cellOskDialogLoadAsync(container=0x%x, dialogParam=*0x%x, inputFieldInfo=*0x%x)", container, dialogParam, inputFieldInfo);
if (!inputFieldInfo || !inputFieldInfo->message || !inputFieldInfo->init_text || inputFieldInfo->limit_length > CELL_OSKDIALOG_STRING_SIZE)
if (!dialogParam || !inputFieldInfo || !inputFieldInfo->message || !inputFieldInfo->init_text || inputFieldInfo->limit_length > CELL_OSKDIALOG_STRING_SIZE)
{
return CELL_OSKDIALOG_ERROR_PARAM;
}
@ -52,8 +52,11 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
return CELL_SYSUTIL_ERROR_BUSY;
}
// Get max length of the return value
// Get the OSK options
u32 maxLength = (inputFieldInfo->limit_length >= CELL_OSKDIALOG_STRING_SIZE) ? 511 : (u32)inputFieldInfo->limit_length;
u32 options = dialogParam->prohibitFlgs;
bool use_seperate_windows = false; // TODO
bool keep_dialog_open = false; // TODO maybe same as use_seperate_windows
// Get init text and prepare return value
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK;
@ -84,28 +87,15 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
bool result = false;
osk->on_close = [&maxLength, wptr = std::weak_ptr<OskDialogBase>(osk)](s32 status)
osk->on_close = [maxLength, use_seperate_windows, keep_dialog_open, wptr = std::weak_ptr<OskDialogBase>(osk)](s32 status)
{
const auto osk = wptr.lock();
osk->state = OskDialogState::Close;
if (status != CELL_MSGDIALOG_BUTTON_OK)
{
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED;
const bool accepted = status == CELL_MSGDIALOG_BUTTON_OK;
if (false/* TODO: check for seperate window */)
{
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0);
}
}
else
if (accepted)
{
if (osk->osk_text[0] == 0 && false/* TODO: check for seperate window */)
{
cellOskDialog.warning("cellOskDialogLoadAsync: input result is CELL_OSKDIALOG_INPUT_FIELD_RESULT_NO_INPUT_TEXT");
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_NO_INPUT_TEXT;
}
if (osk->osk_confirm_callback)
{
vm::ptr<u16> string_to_send = vm::cast(vm::alloc(CELL_OSKDIALOG_STRING_SIZE * 2, vm::main));
@ -133,24 +123,68 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
return 0;
});
// wait for check callback
while (done == false)
{
// wait for check callback
std::this_thread::yield();
}
// reset this here (just to make sure it's null)
osk->osk_confirm_callback = vm::null;
}
if (use_seperate_windows)
{
if (osk->osk_text[0] == 0)
{
cellOskDialog.warning("cellOskDialogLoadAsync: input result is CELL_OSKDIALOG_INPUT_FIELD_RESULT_NO_INPUT_TEXT");
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_NO_INPUT_TEXT;
}
else
{
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK;
}
}
else
{
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_OK;
}
}
else
{
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_CANCELED;
}
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
// Send OSK status
if (use_seperate_windows)
{
if (accepted)
{
if (keep_dialog_open)
{
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_ENTERED, 0);
}
else
{
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
}
}
else
{
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0);
}
}
else
{
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
}
pad::SetIntercepted(false);
};
osk->on_osk_input_entered = [&]()
osk->on_osk_input_entered = [=]()
{
if (false/* TODO: check for seperate window */)
if (use_seperate_windows)
{
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_ENTERED, 0);
}
@ -158,9 +192,9 @@ error_code cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dia
pad::SetIntercepted(true);
Emu.CallAfter([&]()
Emu.CallAfter([=, &result]()
{
osk->Create("On Screen Keyboard", message, osk->osk_text, maxLength);
osk->Create("On Screen Keyboard", message, osk->osk_text, maxLength, options);
result = true;
});
@ -274,7 +308,8 @@ error_code cellOskDialogAbort()
}
osk->osk_input_result = CELL_OSKDIALOG_INPUT_FIELD_RESULT_ABORT;
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
osk->Close(false);
return CELL_OK;
}
@ -365,9 +400,20 @@ error_code cellOskDialogExtEnableClipboard()
return CELL_OK;
}
error_code cellOskDialogExtSendFinishMessage(s32 /*CellOskDialogFinishReason*/ finishReason)
error_code cellOskDialogExtSendFinishMessage(u32 /*CellOskDialogFinishReason*/ finishReason)
{
cellOskDialog.todo("cellOskDialogExtSendFinishMessage(finishReason=%d)", finishReason);
cellOskDialog.warning("cellOskDialogExtSendFinishMessage(finishReason=%d)", finishReason);
const auto osk = fxm::get<OskDialogBase>();
// Check for open dialog.
if (!osk || osk->state.load() != OskDialogState::Open)
{
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
}
osk->Close(finishReason == CELL_OSKDIALOG_CLOSE_CONFIRM);
return CELL_OK;
}

View file

@ -243,7 +243,8 @@ enum class OskDialogState
class OskDialogBase
{
public:
virtual void Create(const std::string& title, const std::u16string& message, char16_t* init_text, u32 charlimit) = 0;
virtual void Create(const std::string& title, const std::u16string& message, char16_t* init_text, u32 charlimit, u32 options) = 0;
virtual void Close(bool accepted) = 0;
virtual ~OskDialogBase();
std::function<void(s32 status)> on_close;

View file

@ -1,12 +1,14 @@

#include "osk_dialog_frame.h"
#include "Emu/Cell/Modules/cellMsgDialog.h"
#include <QLabel>
#include <QLineEdit>
#include <QTextEdit>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QPushButton>
#include <QRegExpValidator>
constexpr auto qstr = QString::fromStdString;
@ -22,7 +24,7 @@ osk_dialog_frame::~osk_dialog_frame()
}
}
void osk_dialog_frame::Create(const std::string& title, const std::u16string& message, char16_t* init_text, u32 charlimit)
void osk_dialog_frame::Create(const std::string& title, const std::u16string& message, char16_t* init_text, u32 charlimit, u32 options)
{
state = OskDialogState::Open;
@ -43,15 +45,9 @@ void osk_dialog_frame::Create(const std::string& title, const std::u16string& me
// Message
QLabel* message_label = new QLabel(QString::fromStdU16String(message));
// Text Input
QLineEdit* input = new QLineEdit(m_dialog);
input->setFixedWidth(lineEditWidth());
input->setMaxLength(charlimit);
input->setText(QString::fromStdU16String(std::u16string(init_text)));
input->setFocus();
// Text Input Counter
QLabel* inputCount = new QLabel(QString("%1/%2").arg(input->text().length()).arg(charlimit));
const QString text = QString::fromStdU16String(std::u16string(init_text));
QLabel* inputCount = new QLabel(QString("%1/%2").arg(text.length()).arg(charlimit));
// Ok Button
QPushButton* button_ok = new QPushButton("Ok", m_dialog);
@ -66,7 +62,63 @@ void osk_dialog_frame::Create(const std::string& title, const std::u16string& me
// Input Layout
QHBoxLayout* inputLayout = new QHBoxLayout;
inputLayout->setAlignment(Qt::AlignHCenter);
inputLayout->addWidget(input);
// Text Input
if (options & CELL_OSKDIALOG_NO_RETURN)
{
QLineEdit* input = new QLineEdit(m_dialog);
input->setFixedWidth(lineEditWidth());
input->setMaxLength(charlimit);
input->setText(text);
input->setFocus();
if (options & CELL_OSKDIALOG_NO_SPACE)
{
input->setValidator(new QRegExpValidator(QRegExp("^\S*$"), this));
}
connect(input, &QLineEdit::textChanged, [=](const QString& text)
{
inputCount->setText(QString("%1/%2").arg(text.length()).arg(charlimit));
SetOskText(text);
on_osk_input_entered();
});
connect(input, &QLineEdit::returnPressed, m_dialog, &QDialog::accept);
inputLayout->addWidget(input);
}
else
{
QTextEdit* input = new QTextEdit(m_dialog);
input->setFixedWidth(lineEditWidth());
input->setText(text);
input->setFocus();
connect(input, &QTextEdit::textChanged, [=]()
{
QString text = input->toPlainText();
text.chop(text.length() - charlimit);
if (options & CELL_OSKDIALOG_NO_SPACE)
{
text.remove(QRegExp("\\s+"));
}
input->setPlainText(text);
QTextCursor cursor = input->textCursor();
cursor.setPosition(QTextCursor::End);
input->setTextCursor(cursor);
inputCount->setText(QString("%1/%2").arg(text.length()).arg(charlimit));
SetOskText(text);
on_osk_input_entered();
});
inputLayout->addWidget(input);
}
inputLayout->addWidget(inputCount);
QFormLayout* layout = new QFormLayout(m_dialog);
@ -77,18 +129,10 @@ void osk_dialog_frame::Create(const std::string& title, const std::u16string& me
m_dialog->setLayout(layout);
// Events
connect(input, &QLineEdit::textChanged, [=](const QString& text)
{
inputCount->setText(QString("%1/%2").arg(text.length()).arg(charlimit));
on_osk_input_entered();
});
connect(input, &QLineEdit::returnPressed, m_dialog, &QDialog::accept);
connect(button_ok, &QAbstractButton::clicked, m_dialog, &QDialog::accept);
connect(m_dialog, &QDialog::accepted, [=]
{
std::memcpy(osk_text, reinterpret_cast<const char16_t*>(input->text().constData()), ((input->text()).size() + 1) * sizeof(char16_t));
on_close(CELL_MSGDIALOG_BUTTON_OK);
});
@ -101,3 +145,16 @@ void osk_dialog_frame::Create(const std::string& title, const std::u16string& me
m_dialog->layout()->setSizeConstraint(QLayout::SetFixedSize);
m_dialog->show();
}
void osk_dialog_frame::SetOskText(const QString& text)
{
std::memcpy(osk_text, reinterpret_cast<const char16_t*>(text.constData()), size_t(text.size() + 1) * sizeof(char16_t));
}
void osk_dialog_frame::Close(bool accepted)
{
if (m_dialog)
{
m_dialog->done(accepted ? QDialog::Accepted : QDialog::Rejected);
}
}

View file

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "stdafx.h"
#include "Emu/Memory/vm.h"
@ -15,8 +15,11 @@ class osk_dialog_frame : public QObject, public OskDialogBase
public:
osk_dialog_frame();
~osk_dialog_frame();
virtual void Create(const std::string& title, const std::u16string& message, char16_t* init_text, u32 charlimit) override;
virtual void Create(const std::string& title, const std::u16string& message, char16_t* init_text, u32 charlimit, u32 options) override;
virtual void Close(bool accepted) override;
private:
void SetOskText(const QString& text);
custom_dialog* m_dialog = nullptr;
};