// Copyright 2018 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include #include #include #include #include #include #include "core/hle/lock.h" #include "yuzu/applets/software_keyboard.h" #include "yuzu/main.h" QtSoftwareKeyboardValidator::QtSoftwareKeyboardValidator( Core::Frontend::SoftwareKeyboardParameters parameters) : parameters(std::move(parameters)) {} QValidator::State QtSoftwareKeyboardValidator::validate(QString& input, int& pos) const { if (input.size() > static_cast(parameters.max_length)) { return Invalid; } if (parameters.disable_space && input.contains(QLatin1Char{' '})) { return Invalid; } if (parameters.disable_address && input.contains(QLatin1Char{'@'})) { return Invalid; } if (parameters.disable_percent && input.contains(QLatin1Char{'%'})) { return Invalid; } if (parameters.disable_slash && (input.contains(QLatin1Char{'/'}) || input.contains(QLatin1Char{'\\'}))) { return Invalid; } if (parameters.disable_number && std::any_of(input.begin(), input.end(), [](QChar c) { return c.isDigit(); })) { return Invalid; } if (parameters.disable_download_code && std::any_of(input.begin(), input.end(), [](QChar c) { return c == QLatin1Char{'O'} || c == QLatin1Char{'I'}; })) { return Invalid; } return Acceptable; } QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( QWidget* parent, Core::Frontend::SoftwareKeyboardParameters parameters_) : QDialog(parent), parameters(std::move(parameters_)) { layout = new QVBoxLayout; header_label = new QLabel(QString::fromStdU16String(parameters.header_text)); header_label->setFont({header_label->font().family(), 11, QFont::Bold}); if (header_label->text().isEmpty()) header_label->setText(tr("Enter text:")); sub_label = new QLabel(QString::fromStdU16String(parameters.sub_text)); sub_label->setFont({sub_label->font().family(), sub_label->font().pointSize(), sub_label->font().weight(), true}); sub_label->setHidden(parameters.sub_text.empty()); guide_label = new QLabel(QString::fromStdU16String(parameters.guide_text)); guide_label->setHidden(parameters.guide_text.empty()); length_label = new QLabel(QStringLiteral("0/%1").arg(parameters.max_length)); length_label->setAlignment(Qt::AlignRight); length_label->setFont({length_label->font().family(), 8}); line_edit = new QLineEdit; line_edit->setValidator(new QtSoftwareKeyboardValidator(parameters)); line_edit->setMaxLength(static_cast(parameters.max_length)); line_edit->setText(QString::fromStdU16String(parameters.initial_text)); line_edit->setCursorPosition( parameters.cursor_at_beginning ? 0 : static_cast(parameters.initial_text.size())); line_edit->setEchoMode(parameters.password ? QLineEdit::Password : QLineEdit::Normal); connect(line_edit, &QLineEdit::textChanged, this, [this](const QString& text) { length_label->setText(QStringLiteral("%1/%2").arg(text.size()).arg(parameters.max_length)); }); buttons = new QDialogButtonBox(QDialogButtonBox::Cancel); if (parameters.submit_text.empty()) { buttons->addButton(QDialogButtonBox::Ok); } else { buttons->addButton(QString::fromStdU16String(parameters.submit_text), QDialogButtonBox::AcceptRole); } connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept); connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject); layout->addWidget(header_label); layout->addWidget(sub_label); layout->addWidget(guide_label); layout->addWidget(length_label); layout->addWidget(line_edit); layout->addWidget(buttons); setLayout(layout); setWindowTitle(tr("Software Keyboard")); } QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; void QtSoftwareKeyboardDialog::accept() { ok = true; text = line_edit->text().toStdU16String(); QDialog::accept(); } void QtSoftwareKeyboardDialog::reject() { ok = false; text.clear(); QDialog::reject(); } std::u16string QtSoftwareKeyboardDialog::GetText() const { return text; } bool QtSoftwareKeyboardDialog::GetStatus() const { return ok; } QtSoftwareKeyboard::QtSoftwareKeyboard(GMainWindow& main_window) { connect(this, &QtSoftwareKeyboard::MainWindowGetText, &main_window, &GMainWindow::SoftwareKeyboardGetText, Qt::QueuedConnection); connect(this, &QtSoftwareKeyboard::MainWindowTextCheckDialog, &main_window, &GMainWindow::SoftwareKeyboardInvokeCheckDialog, Qt::BlockingQueuedConnection); connect(&main_window, &GMainWindow::SoftwareKeyboardFinishedText, this, &QtSoftwareKeyboard::MainWindowFinishedText, Qt::QueuedConnection); } QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; void QtSoftwareKeyboard::RequestText(std::function)> out, Core::Frontend::SoftwareKeyboardParameters parameters) const { text_output = std::move(out); emit MainWindowGetText(parameters); } void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, std::function finished_check) const { this->finished_check = std::move(finished_check); emit MainWindowTextCheckDialog(error_message); } void QtSoftwareKeyboard::MainWindowFinishedText(std::optional text) { // Acquire the HLE mutex std::lock_guard lock{HLE::g_hle_lock}; text_output(std::move(text)); } void QtSoftwareKeyboard::MainWindowFinishedCheckDialog() { // Acquire the HLE mutex std::lock_guard lock{HLE::g_hle_lock}; finished_check(); }