remove old files

This commit is contained in:
mgthepro
2022-01-24 11:43:50 +01:00
parent 87def5b55b
commit ae416cfe9f
8874 changed files with 0 additions and 2090184 deletions
-695
View File
@@ -1,695 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <thread>
#include "common/assert.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/lock.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/sm/sm.h"
#include "ui_controller.h"
#include "yuzu/applets/controller.h"
#include "yuzu/configuration/configure_input.h"
#include "yuzu/configuration/configure_input_profile_dialog.h"
#include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_vibration.h"
#include "yuzu/configuration/input_profiles.h"
#include "yuzu/main.h"
namespace {
constexpr std::size_t HANDHELD_INDEX = 8;
constexpr std::array<std::array<bool, 4>, 8> led_patterns{{
{true, false, false, false},
{true, true, false, false},
{true, true, true, false},
{true, true, true, true},
{true, false, false, true},
{true, false, true, false},
{true, false, true, true},
{false, true, true, false},
}};
void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
bool connected) {
Core::System& system{Core::System::GetInstance()};
if (!system.IsPoweredOn()) {
return;
}
Service::SM::ServiceManager& sm = system.ServiceManager();
auto& npad =
sm.GetService<Service::HID::Hid>("hid")
->GetAppletResource()
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
}
// Returns true if the given controller type is compatible with the given parameters.
bool IsControllerCompatible(Settings::ControllerType controller_type,
Core::Frontend::ControllerParameters parameters) {
switch (controller_type) {
case Settings::ControllerType::ProController:
return parameters.allow_pro_controller;
case Settings::ControllerType::DualJoyconDetached:
return parameters.allow_dual_joycons;
case Settings::ControllerType::LeftJoycon:
return parameters.allow_left_joycon;
case Settings::ControllerType::RightJoycon:
return parameters.allow_right_joycon;
case Settings::ControllerType::Handheld:
return parameters.enable_single_mode && parameters.allow_handheld;
case Settings::ControllerType::GameCube:
return parameters.allow_gamecube_controller;
default:
return false;
}
}
} // namespace
QtControllerSelectorDialog::QtControllerSelectorDialog(
QWidget* parent, Core::Frontend::ControllerParameters parameters_,
InputCommon::InputSubsystem* input_subsystem_)
: QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
parameters(std::move(parameters_)), input_subsystem{input_subsystem_},
input_profiles(std::make_unique<InputProfiles>()) {
ui->setupUi(this);
player_widgets = {
ui->widgetPlayer1, ui->widgetPlayer2, ui->widgetPlayer3, ui->widgetPlayer4,
ui->widgetPlayer5, ui->widgetPlayer6, ui->widgetPlayer7, ui->widgetPlayer8,
};
player_groupboxes = {
ui->groupPlayer1Connected, ui->groupPlayer2Connected, ui->groupPlayer3Connected,
ui->groupPlayer4Connected, ui->groupPlayer5Connected, ui->groupPlayer6Connected,
ui->groupPlayer7Connected, ui->groupPlayer8Connected,
};
connected_controller_icons = {
ui->controllerPlayer1, ui->controllerPlayer2, ui->controllerPlayer3, ui->controllerPlayer4,
ui->controllerPlayer5, ui->controllerPlayer6, ui->controllerPlayer7, ui->controllerPlayer8,
};
led_patterns_boxes = {{
{ui->checkboxPlayer1LED1, ui->checkboxPlayer1LED2, ui->checkboxPlayer1LED3,
ui->checkboxPlayer1LED4},
{ui->checkboxPlayer2LED1, ui->checkboxPlayer2LED2, ui->checkboxPlayer2LED3,
ui->checkboxPlayer2LED4},
{ui->checkboxPlayer3LED1, ui->checkboxPlayer3LED2, ui->checkboxPlayer3LED3,
ui->checkboxPlayer3LED4},
{ui->checkboxPlayer4LED1, ui->checkboxPlayer4LED2, ui->checkboxPlayer4LED3,
ui->checkboxPlayer4LED4},
{ui->checkboxPlayer5LED1, ui->checkboxPlayer5LED2, ui->checkboxPlayer5LED3,
ui->checkboxPlayer5LED4},
{ui->checkboxPlayer6LED1, ui->checkboxPlayer6LED2, ui->checkboxPlayer6LED3,
ui->checkboxPlayer6LED4},
{ui->checkboxPlayer7LED1, ui->checkboxPlayer7LED2, ui->checkboxPlayer7LED3,
ui->checkboxPlayer7LED4},
{ui->checkboxPlayer8LED1, ui->checkboxPlayer8LED2, ui->checkboxPlayer8LED3,
ui->checkboxPlayer8LED4},
}};
explain_text_labels = {
ui->labelPlayer1Explain, ui->labelPlayer2Explain, ui->labelPlayer3Explain,
ui->labelPlayer4Explain, ui->labelPlayer5Explain, ui->labelPlayer6Explain,
ui->labelPlayer7Explain, ui->labelPlayer8Explain,
};
emulated_controllers = {
ui->comboPlayer1Emulated, ui->comboPlayer2Emulated, ui->comboPlayer3Emulated,
ui->comboPlayer4Emulated, ui->comboPlayer5Emulated, ui->comboPlayer6Emulated,
ui->comboPlayer7Emulated, ui->comboPlayer8Emulated,
};
player_labels = {
ui->labelPlayer1, ui->labelPlayer2, ui->labelPlayer3, ui->labelPlayer4,
ui->labelPlayer5, ui->labelPlayer6, ui->labelPlayer7, ui->labelPlayer8,
};
connected_controller_labels = {
ui->labelConnectedPlayer1, ui->labelConnectedPlayer2, ui->labelConnectedPlayer3,
ui->labelConnectedPlayer4, ui->labelConnectedPlayer5, ui->labelConnectedPlayer6,
ui->labelConnectedPlayer7, ui->labelConnectedPlayer8,
};
connected_controller_checkboxes = {
ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected,
ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected,
ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
};
// Setup/load everything prior to setting up connections.
// This avoids unintentionally changing the states of elements while loading them in.
SetSupportedControllers();
DisableUnsupportedPlayers();
for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) {
SetEmulatedControllers(player_index);
}
LoadConfiguration();
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
SetExplainText(i);
UpdateControllerIcon(i);
UpdateLEDPattern(i);
UpdateBorderColor(i);
connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) {
if (checked) {
for (std::size_t index = 0; index <= i; ++index) {
connected_controller_checkboxes[index]->setChecked(checked);
}
} else {
for (std::size_t index = i; index < NUM_PLAYERS; ++index) {
connected_controller_checkboxes[index]->setChecked(checked);
}
}
});
connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
[this, i](int) {
UpdateControllerIcon(i);
UpdateControllerState(i);
UpdateLEDPattern(i);
CheckIfParametersMet();
});
connect(connected_controller_checkboxes[i], &QCheckBox::stateChanged, [this, i](int state) {
player_groupboxes[i]->setChecked(state == Qt::Checked);
UpdateControllerIcon(i);
UpdateControllerState(i);
UpdateLEDPattern(i);
UpdateBorderColor(i);
CheckIfParametersMet();
});
if (i == 0) {
connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
[this, i](int index) {
UpdateDockedState(GetControllerTypeFromIndex(index, i) ==
Settings::ControllerType::Handheld);
});
}
}
connect(ui->vibrationButton, &QPushButton::clicked, this,
&QtControllerSelectorDialog::CallConfigureVibrationDialog);
connect(ui->motionButton, &QPushButton::clicked, this,
&QtControllerSelectorDialog::CallConfigureMotionTouchDialog);
connect(ui->inputConfigButton, &QPushButton::clicked, this,
&QtControllerSelectorDialog::CallConfigureInputProfileDialog);
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
&QtControllerSelectorDialog::ApplyConfiguration);
// Enhancement: Check if the parameters have already been met before disconnecting controllers.
// If all the parameters are met AND only allows a single player,
// stop the constructor here as we do not need to continue.
if (CheckIfParametersMet() && parameters.enable_single_mode) {
return;
}
// If keep_controllers_connected is false, forcefully disconnect all controllers
if (!parameters.keep_controllers_connected) {
for (auto player : player_groupboxes) {
player->setChecked(false);
}
}
resize(0, 0);
}
QtControllerSelectorDialog::~QtControllerSelectorDialog() = default;
int QtControllerSelectorDialog::exec() {
if (parameters_met && parameters.enable_single_mode) {
return QDialog::Accepted;
}
return QDialog::exec();
}
void QtControllerSelectorDialog::ApplyConfiguration() {
const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
Settings::values.use_docked_mode.SetValue(ui->radioDocked->isChecked());
OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode.GetValue());
Settings::values.vibration_enabled.SetValue(ui->vibrationGroup->isChecked());
Settings::values.motion_enabled.SetValue(ui->motionGroup->isChecked());
}
void QtControllerSelectorDialog::LoadConfiguration() {
for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
const auto connected =
Settings::values.players.GetValue()[index].connected ||
(index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
player_groupboxes[index]->setChecked(connected);
connected_controller_checkboxes[index]->setChecked(connected);
emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType(
Settings::values.players.GetValue()[index].controller_type, index));
}
UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
}
void QtControllerSelectorDialog::CallConfigureVibrationDialog() {
ConfigureVibration dialog(this);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Accepted) {
dialog.ApplyConfiguration();
}
}
void QtControllerSelectorDialog::CallConfigureMotionTouchDialog() {
ConfigureMotionTouch dialog(this, input_subsystem);
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Accepted) {
dialog.ApplyConfiguration();
}
}
void QtControllerSelectorDialog::CallConfigureInputProfileDialog() {
ConfigureInputProfileDialog dialog(this, input_subsystem, input_profiles.get());
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowSystemMenuHint);
dialog.setWindowModality(Qt::WindowModal);
dialog.exec();
}
bool QtControllerSelectorDialog::CheckIfParametersMet() {
// Here, we check and validate the current configuration against all applicable parameters.
const auto num_connected_players = static_cast<int>(
std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
[this](const QGroupBox* player) { return player->isChecked(); }));
const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players;
const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
// First, check against the number of connected players.
if (num_connected_players < min_supported_players ||
num_connected_players > max_supported_players) {
parameters_met = false;
ui->buttonBox->setEnabled(parameters_met);
return parameters_met;
}
// Next, check against all connected controllers.
const auto all_controllers_compatible = [this] {
for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
// Skip controllers that are not used, we only care about the currently connected ones.
if (!player_groupboxes[index]->isChecked() || !player_groupboxes[index]->isEnabled()) {
continue;
}
const auto compatible = IsControllerCompatible(
GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex(), index),
parameters);
// If any controller is found to be incompatible, return false early.
if (!compatible) {
return false;
}
}
// Reaching here means all currently connected controllers are compatible.
return true;
}();
parameters_met = all_controllers_compatible;
ui->buttonBox->setEnabled(parameters_met);
return parameters_met;
}
void QtControllerSelectorDialog::SetSupportedControllers() {
const QString theme = [] {
if (QIcon::themeName().contains(QStringLiteral("dark"))) {
return QStringLiteral("_dark");
} else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
return QStringLiteral("_midnight");
} else {
return QString{};
}
}();
if (parameters.enable_single_mode && parameters.allow_handheld) {
ui->controllerSupported1->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_handheld%0); ").arg(theme));
} else {
ui->controllerSupported1->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_handheld%0_disabled); ").arg(theme));
}
if (parameters.allow_dual_joycons) {
ui->controllerSupported2->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ").arg(theme));
} else {
ui->controllerSupported2->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_dual_joycon%0_disabled); ").arg(theme));
}
if (parameters.allow_left_joycon) {
ui->controllerSupported3->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_joycon_left%0); ").arg(theme));
} else {
ui->controllerSupported3->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_joycon_left%0_disabled); ").arg(theme));
}
if (parameters.allow_right_joycon) {
ui->controllerSupported4->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_joycon_right%0); ").arg(theme));
} else {
ui->controllerSupported4->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme));
}
if (parameters.allow_pro_controller || parameters.allow_gamecube_controller) {
ui->controllerSupported5->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme));
} else {
ui->controllerSupported5->setStyleSheet(
QStringLiteral("image: url(:/controller/applet_pro_controller%0_disabled); ")
.arg(theme));
}
// enable_single_mode overrides min_players and max_players.
if (parameters.enable_single_mode) {
ui->numberSupportedLabel->setText(QStringLiteral("1"));
return;
}
if (parameters.min_players == parameters.max_players) {
ui->numberSupportedLabel->setText(QStringLiteral("%1").arg(parameters.max_players));
} else {
ui->numberSupportedLabel->setText(
QStringLiteral("%1 - %2").arg(parameters.min_players).arg(parameters.max_players));
}
}
void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) {
auto& pairs = index_controller_type_pairs[player_index];
pairs.clear();
emulated_controllers[player_index]->clear();
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::ProController);
emulated_controllers[player_index]->addItem(tr("Pro Controller"));
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::DualJoyconDetached);
emulated_controllers[player_index]->addItem(tr("Dual Joycons"));
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::LeftJoycon);
emulated_controllers[player_index]->addItem(tr("Left Joycon"));
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::RightJoycon);
emulated_controllers[player_index]->addItem(tr("Right Joycon"));
if (player_index == 0) {
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::Handheld);
emulated_controllers[player_index]->addItem(tr("Handheld"));
}
pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::GameCube);
emulated_controllers[player_index]->addItem(tr("GameCube Controller"));
}
Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
int index, std::size_t player_index) const {
const auto& pairs = index_controller_type_pairs[player_index];
const auto it = std::find_if(pairs.begin(), pairs.end(),
[index](const auto& pair) { return pair.first == index; });
if (it == pairs.end()) {
return Settings::ControllerType::ProController;
}
return it->second;
}
int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type,
std::size_t player_index) const {
const auto& pairs = index_controller_type_pairs[player_index];
const auto it = std::find_if(pairs.begin(), pairs.end(),
[type](const auto& pair) { return pair.second == type; });
if (it == pairs.end()) {
return 0;
}
return it->first;
}
void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) {
if (!player_groupboxes[player_index]->isChecked()) {
connected_controller_icons[player_index]->setStyleSheet(QString{});
player_labels[player_index]->show();
return;
}
const QString stylesheet = [this, player_index] {
switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
player_index)) {
case Settings::ControllerType::ProController:
case Settings::ControllerType::GameCube:
return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
case Settings::ControllerType::DualJoyconDetached:
return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
case Settings::ControllerType::LeftJoycon:
return QStringLiteral("image: url(:/controller/applet_joycon_left%0); ");
case Settings::ControllerType::RightJoycon:
return QStringLiteral("image: url(:/controller/applet_joycon_right%0); ");
case Settings::ControllerType::Handheld:
return QStringLiteral("image: url(:/controller/applet_handheld%0); ");
default:
return QString{};
}
}();
if (stylesheet.isEmpty()) {
connected_controller_icons[player_index]->setStyleSheet(QString{});
player_labels[player_index]->show();
return;
}
const QString theme = [] {
if (QIcon::themeName().contains(QStringLiteral("dark"))) {
return QStringLiteral("_dark");
} else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
return QStringLiteral("_midnight");
} else {
return QString{};
}
}();
connected_controller_icons[player_index]->setStyleSheet(stylesheet.arg(theme));
player_labels[player_index]->hide();
}
void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
auto& player = Settings::values.players.GetValue()[player_index];
const auto controller_type = GetControllerTypeFromIndex(
emulated_controllers[player_index]->currentIndex(), player_index);
const auto player_connected = player_groupboxes[player_index]->isChecked() &&
controller_type != Settings::ControllerType::Handheld;
if (player.controller_type == controller_type && player.connected == player_connected) {
// Set vibration devices in the event that the input device has changed.
ConfigureVibration::SetVibrationDevices(player_index);
return;
}
// Disconnect the controller first.
UpdateController(controller_type, player_index, false);
player.controller_type = controller_type;
player.connected = player_connected;
ConfigureVibration::SetVibrationDevices(player_index);
// Handheld
if (player_index == 0) {
auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX];
if (controller_type == Settings::ControllerType::Handheld) {
handheld = player;
}
handheld.connected = player_groupboxes[player_index]->isChecked() &&
controller_type == Settings::ControllerType::Handheld;
UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected);
}
if (!player.connected) {
return;
}
// This emulates a delay between disconnecting and reconnecting controllers as some games
// do not respond to a change in controller type if it was instantaneous.
using namespace std::chrono_literals;
std::this_thread::sleep_for(60ms);
UpdateController(controller_type, player_index, player_connected);
}
void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
if (!player_groupboxes[player_index]->isChecked() ||
GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
player_index) == Settings::ControllerType::Handheld) {
led_patterns_boxes[player_index][0]->setChecked(false);
led_patterns_boxes[player_index][1]->setChecked(false);
led_patterns_boxes[player_index][2]->setChecked(false);
led_patterns_boxes[player_index][3]->setChecked(false);
return;
}
led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]);
led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]);
led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]);
led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]);
}
void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) {
if (!parameters.enable_border_color ||
player_index >= static_cast<std::size_t>(parameters.max_players) ||
player_groupboxes[player_index]->styleSheet().contains(QStringLiteral("QGroupBox"))) {
return;
}
player_groupboxes[player_index]->setStyleSheet(
player_groupboxes[player_index]->styleSheet().append(
QStringLiteral("QGroupBox#groupPlayer%1Connected:checked "
"{ border: 1px solid rgba(%2, %3, %4, %5); }")
.arg(player_index + 1)
.arg(parameters.border_colors[player_index][0])
.arg(parameters.border_colors[player_index][1])
.arg(parameters.border_colors[player_index][2])
.arg(parameters.border_colors[player_index][3])));
}
void QtControllerSelectorDialog::SetExplainText(std::size_t player_index) {
if (!parameters.enable_explain_text ||
player_index >= static_cast<std::size_t>(parameters.max_players)) {
return;
}
explain_text_labels[player_index]->setText(QString::fromStdString(
Common::StringFromFixedZeroTerminatedBuffer(parameters.explain_text[player_index].data(),
parameters.explain_text[player_index].size())));
}
void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) {
// Disallow changing the console mode if the controller type is handheld.
ui->radioDocked->setEnabled(!is_handheld);
ui->radioUndocked->setEnabled(!is_handheld);
ui->radioDocked->setChecked(Settings::values.use_docked_mode.GetValue());
ui->radioUndocked->setChecked(!Settings::values.use_docked_mode.GetValue());
// Also force into undocked mode if the controller type is handheld.
if (is_handheld) {
ui->radioUndocked->setChecked(true);
}
}
void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
switch (max_supported_players) {
case 0:
default:
UNREACHABLE();
return;
case 1:
ui->widgetSpacer->hide();
ui->widgetSpacer2->hide();
ui->widgetSpacer3->hide();
ui->widgetSpacer4->hide();
break;
case 2:
ui->widgetSpacer->hide();
ui->widgetSpacer2->hide();
ui->widgetSpacer3->hide();
break;
case 3:
ui->widgetSpacer->hide();
ui->widgetSpacer2->hide();
break;
case 4:
ui->widgetSpacer->hide();
break;
case 5:
case 6:
case 7:
case 8:
break;
}
for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
// Disconnect any unsupported players here and disable or hide them if applicable.
Settings::values.players.GetValue()[index].connected = false;
UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false);
// Hide the player widgets when max_supported_controllers is less than or equal to 4.
if (max_supported_players <= 4) {
player_widgets[index]->hide();
}
// Disable and hide the following to prevent these from interaction.
player_widgets[index]->setDisabled(true);
connected_controller_checkboxes[index]->setDisabled(true);
connected_controller_labels[index]->hide();
connected_controller_checkboxes[index]->hide();
}
}
QtControllerSelector::QtControllerSelector(GMainWindow& parent) {
connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent,
&GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this,
&QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection);
}
QtControllerSelector::~QtControllerSelector() = default;
void QtControllerSelector::ReconfigureControllers(
std::function<void()> callback_, const Core::Frontend::ControllerParameters& parameters) const {
callback = std::move(callback_);
emit MainWindowReconfigureControllers(parameters);
}
void QtControllerSelector::MainWindowReconfigureFinished() {
// Acquire the HLE mutex
std::lock_guard lock(HLE::g_hle_lock);
callback();
}
-164
View File
@@ -1,164 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <memory>
#include <QDialog>
#include "core/frontend/applets/controller.h"
class GMainWindow;
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
class QGroupBox;
class QLabel;
class InputProfiles;
namespace InputCommon {
class InputSubsystem;
}
namespace Settings {
enum class ControllerType;
}
namespace Ui {
class QtControllerSelectorDialog;
}
class QtControllerSelectorDialog final : public QDialog {
Q_OBJECT
public:
explicit QtControllerSelectorDialog(QWidget* parent,
Core::Frontend::ControllerParameters parameters_,
InputCommon::InputSubsystem* input_subsystem_);
~QtControllerSelectorDialog() override;
int exec() override;
private:
// Applies the current configuration.
void ApplyConfiguration();
// Loads the current input configuration into the frontend applet.
void LoadConfiguration();
// Initializes the "Configure Vibration" Dialog.
void CallConfigureVibrationDialog();
// Initializes the "Configure Motion / Touch" Dialog.
void CallConfigureMotionTouchDialog();
// Initializes the "Create Input Profile" Dialog.
void CallConfigureInputProfileDialog();
// Checks the current configuration against the given parameters.
// This sets and returns the value of parameters_met.
bool CheckIfParametersMet();
// Sets the controller icons for "Supported Controller Types".
void SetSupportedControllers();
// Sets the emulated controllers per player.
void SetEmulatedControllers(std::size_t player_index);
// Gets the Controller Type for a given controller combobox index per player.
Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const;
// Gets the controller combobox index for a given Controller Type per player.
int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const;
// Updates the controller icons per player.
void UpdateControllerIcon(std::size_t player_index);
// Updates the controller state (type and connection status) per player.
void UpdateControllerState(std::size_t player_index);
// Updates the LED pattern per player.
void UpdateLEDPattern(std::size_t player_index);
// Updates the border color per player.
void UpdateBorderColor(std::size_t player_index);
// Sets the "Explain Text" per player.
void SetExplainText(std::size_t player_index);
// Updates the console mode.
void UpdateDockedState(bool is_handheld);
// Disables and disconnects unsupported players based on the given parameters.
void DisableUnsupportedPlayers();
std::unique_ptr<Ui::QtControllerSelectorDialog> ui;
// Parameters sent in from the backend HLE applet.
Core::Frontend::ControllerParameters parameters;
InputCommon::InputSubsystem* input_subsystem;
std::unique_ptr<InputProfiles> input_profiles;
// This is true if and only if all parameters are met. Otherwise, this is false.
// This determines whether the "OK" button can be clicked to exit the applet.
bool parameters_met{false};
static constexpr std::size_t NUM_PLAYERS = 8;
// Widgets encapsulating the groupboxes and comboboxes per player.
std::array<QWidget*, NUM_PLAYERS> player_widgets;
// Groupboxes encapsulating the controller icons and LED patterns per player.
std::array<QGroupBox*, NUM_PLAYERS> player_groupboxes;
// Icons for currently connected controllers/players.
std::array<QWidget*, NUM_PLAYERS> connected_controller_icons;
// Labels that represent the player numbers in place of the controller icons.
std::array<QLabel*, NUM_PLAYERS> player_labels;
// LED patterns for currently connected controllers/players.
std::array<std::array<QCheckBox*, 4>, NUM_PLAYERS> led_patterns_boxes;
// Labels representing additional information known as "Explain Text" per player.
std::array<QLabel*, NUM_PLAYERS> explain_text_labels;
// Comboboxes with a list of emulated controllers per player.
std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
/// Pairs of emulated controller index and Controller Type enum per player.
std::array<std::vector<std::pair<int, Settings::ControllerType>>, NUM_PLAYERS>
index_controller_type_pairs;
// Labels representing the number of connected controllers
// above the "Connected Controllers" checkboxes.
std::array<QLabel*, NUM_PLAYERS> connected_controller_labels;
// Checkboxes representing the "Connected Controllers".
std::array<QCheckBox*, NUM_PLAYERS> connected_controller_checkboxes;
};
class QtControllerSelector final : public QObject, public Core::Frontend::ControllerApplet {
Q_OBJECT
public:
explicit QtControllerSelector(GMainWindow& parent);
~QtControllerSelector() override;
void ReconfigureControllers(
std::function<void()> callback_,
const Core::Frontend::ControllerParameters& parameters) const override;
signals:
void MainWindowReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters) const;
private:
void MainWindowReconfigureFinished();
mutable std::function<void()> callback;
};
File diff suppressed because it is too large Load Diff
-63
View File
@@ -1,63 +0,0 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QDateTime>
#include "core/hle/lock.h"
#include "yuzu/applets/error.h"
#include "yuzu/main.h"
QtErrorDisplay::QtErrorDisplay(GMainWindow& parent) {
connect(this, &QtErrorDisplay::MainWindowDisplayError, &parent,
&GMainWindow::ErrorDisplayDisplayError, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ErrorDisplayFinished, this,
&QtErrorDisplay::MainWindowFinishedError, Qt::DirectConnection);
}
QtErrorDisplay::~QtErrorDisplay() = default;
void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const {
callback = std::move(finished);
emit MainWindowDisplayError(
tr("Error Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0')),
tr("An error has occurred.\nPlease try again or contact the developer of the software."));
}
void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
std::function<void()> finished) const {
callback = std::move(finished);
const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count());
emit MainWindowDisplayError(
tr("Error Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0')),
tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the "
"software.")
.arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy")))
.arg(date_time.toString(QStringLiteral("h:mm:ss A"))));
}
void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text,
std::string fullscreen_text,
std::function<void()> finished) const {
callback = std::move(finished);
emit MainWindowDisplayError(
tr("Error Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0')),
tr("An error has occurred.\n\n%1\n\n%2")
.arg(QString::fromStdString(dialog_text))
.arg(QString::fromStdString(fullscreen_text)));
}
void QtErrorDisplay::MainWindowFinishedError() {
// Acquire the HLE mutex
std::lock_guard lock{HLE::g_hle_lock};
callback();
}
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <QObject>
#include "core/frontend/applets/error.h"
class GMainWindow;
class QtErrorDisplay final : public QObject, public Core::Frontend::ErrorApplet {
Q_OBJECT
public:
explicit QtErrorDisplay(GMainWindow& parent);
~QtErrorDisplay() override;
void ShowError(ResultCode error, std::function<void()> finished) const override;
void ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
std::function<void()> finished) const override;
void ShowCustomErrorText(ResultCode error, std::string dialog_text, std::string fullscreen_text,
std::function<void()> finished) const override;
signals:
void MainWindowDisplayError(QString error_code, QString error_text) const;
private:
void MainWindowFinishedError();
mutable std::function<void()> callback;
};
-163
View File
@@ -1,163 +0,0 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <mutex>
#include <QDialogButtonBox>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QScrollArea>
#include <QStandardItemModel>
#include <QVBoxLayout>
#include "common/fs/path_util.h"
#include "common/string_util.h"
#include "core/constants.h"
#include "core/hle/lock.h"
#include "yuzu/applets/profile_select.h"
#include "yuzu/main.h"
namespace {
QString FormatUserEntryText(const QString& username, Common::UUID uuid) {
return QtProfileSelectionDialog::tr(
"%1\n%2", "%1 is the profile username, %2 is the formatted UUID (e.g. "
"00112233-4455-6677-8899-AABBCCDDEEFF))")
.arg(username, QString::fromStdString(uuid.FormatSwitch()));
}
QString GetImagePath(Common::UUID uuid) {
const auto path =
Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) /
fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormatSwitch());
return QString::fromStdString(Common::FS::PathToUTF8String(path));
}
QPixmap GetIcon(Common::UUID uuid) {
QPixmap icon{GetImagePath(uuid)};
if (!icon) {
icon.fill(Qt::black);
icon.loadFromData(Core::Constants::ACCOUNT_BACKUP_JPEG.data(),
static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size()));
}
return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
} // Anonymous namespace
QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
: QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) {
outer_layout = new QVBoxLayout;
instruction_label = new QLabel(tr("Select a user:"));
scroll_area = new QScrollArea;
buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
connect(buttons, &QDialogButtonBox::accepted, this, &QtProfileSelectionDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QtProfileSelectionDialog::reject);
outer_layout->addWidget(instruction_label);
outer_layout->addWidget(scroll_area);
outer_layout->addWidget(buttons);
layout = new QVBoxLayout;
tree_view = new QTreeView;
item_model = new QStandardItemModel(tree_view);
tree_view->setModel(item_model);
tree_view->setAlternatingRowColors(true);
tree_view->setSelectionMode(QHeaderView::SingleSelection);
tree_view->setSelectionBehavior(QHeaderView::SelectRows);
tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel);
tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel);
tree_view->setSortingEnabled(true);
tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
tree_view->setUniformRowHeights(true);
tree_view->setIconSize({64, 64});
tree_view->setContextMenuPolicy(Qt::NoContextMenu);
item_model->insertColumns(0, 1);
item_model->setHeaderData(0, Qt::Horizontal, tr("Users"));
// We must register all custom types with the Qt Automoc system so that we are able to use it
// with signals/slots. In this case, QList falls under the umbrella of custom types.
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
layout->addWidget(tree_view);
scroll_area->setLayout(layout);
connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser);
const auto& profiles = profile_manager->GetAllUsers();
for (const auto& user : profiles) {
Service::Account::ProfileBase profile{};
if (!profile_manager->GetProfileBase(user, profile))
continue;
const auto username = Common::StringFromFixedZeroTerminatedBuffer(
reinterpret_cast<const char*>(profile.username.data()), profile.username.size());
list_items.push_back(QList<QStandardItem*>{new QStandardItem{
GetIcon(user), FormatUserEntryText(QString::fromStdString(username), user)}});
}
for (const auto& item : list_items)
item_model->appendRow(item);
setLayout(outer_layout);
setWindowTitle(tr("Profile Selector"));
resize(550, 400);
}
QtProfileSelectionDialog::~QtProfileSelectionDialog() = default;
int QtProfileSelectionDialog::exec() {
// Skip profile selection when there's only one.
if (profile_manager->GetUserCount() == 1) {
user_index = 0;
return QDialog::Accepted;
}
return QDialog::exec();
}
void QtProfileSelectionDialog::accept() {
QDialog::accept();
}
void QtProfileSelectionDialog::reject() {
user_index = 0;
QDialog::reject();
}
int QtProfileSelectionDialog::GetIndex() const {
return user_index;
}
void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) {
user_index = index.row();
}
QtProfileSelector::QtProfileSelector(GMainWindow& parent) {
connect(this, &QtProfileSelector::MainWindowSelectProfile, &parent,
&GMainWindow::ProfileSelectorSelectProfile, Qt::QueuedConnection);
connect(&parent, &GMainWindow::ProfileSelectorFinishedSelection, this,
&QtProfileSelector::MainWindowFinishedSelection, Qt::DirectConnection);
}
QtProfileSelector::~QtProfileSelector() = default;
void QtProfileSelector::SelectProfile(
std::function<void(std::optional<Common::UUID>)> callback_) const {
callback = std::move(callback_);
emit MainWindowSelectProfile();
}
void QtProfileSelector::MainWindowFinishedSelection(std::optional<Common::UUID> uuid) {
// Acquire the HLE mutex
std::lock_guard lock{HLE::g_hle_lock};
callback(uuid);
}
-72
View File
@@ -1,72 +0,0 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include <QDialog>
#include <QList>
#include <QTreeView>
#include "core/frontend/applets/profile_select.h"
#include "core/hle/service/acc/profile_manager.h"
class GMainWindow;
class QDialogButtonBox;
class QGraphicsScene;
class QLabel;
class QScrollArea;
class QStandardItem;
class QStandardItemModel;
class QVBoxLayout;
class QtProfileSelectionDialog final : public QDialog {
Q_OBJECT
public:
explicit QtProfileSelectionDialog(QWidget* parent);
~QtProfileSelectionDialog() override;
int exec() override;
void accept() override;
void reject() override;
int GetIndex() const;
private:
void SelectUser(const QModelIndex& index);
int user_index = 0;
QVBoxLayout* layout;
QTreeView* tree_view;
QStandardItemModel* item_model;
QGraphicsScene* scene;
std::vector<QList<QStandardItem*>> list_items;
QVBoxLayout* outer_layout;
QLabel* instruction_label;
QScrollArea* scroll_area;
QDialogButtonBox* buttons;
std::unique_ptr<Service::Account::ProfileManager> profile_manager;
};
class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSelectApplet {
Q_OBJECT
public:
explicit QtProfileSelector(GMainWindow& parent);
~QtProfileSelector() override;
void SelectProfile(std::function<void(std::optional<Common::UUID>)> callback_) const override;
signals:
void MainWindowSelectProfile() const;
private:
void MainWindowFinishedSelection(std::optional<Common::UUID> uuid);
mutable std::function<void(std::optional<Common::UUID>)> callback;
};
File diff suppressed because it is too large Load Diff
-285
View File
@@ -1,285 +0,0 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <atomic>
#include <memory>
#include <thread>
#include <QDialog>
#include <QValidator>
#include "core/frontend/applets/software_keyboard.h"
enum class HIDButton : u8;
class InputInterpreter;
namespace Core {
class System;
}
namespace Ui {
class QtSoftwareKeyboardDialog;
}
class GMainWindow;
class QtSoftwareKeyboardDialog final : public QDialog {
Q_OBJECT
public:
QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_,
Core::Frontend::KeyboardInitializeParameters initialize_parameters_);
~QtSoftwareKeyboardDialog() override;
void ShowNormalKeyboard(QPoint pos, QSize size);
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message);
void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos,
QSize size);
void HideInlineKeyboard();
void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
void ExitKeyboard();
signals:
void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
std::u16string submitted_text) const;
void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
std::u16string submitted_text, s32 cursor_position) const;
public slots:
void open() override;
void reject() override;
protected:
/// We override the keyPressEvent for inputting text into the inline software keyboard.
void keyPressEvent(QKeyEvent* event) override;
private:
enum class Direction {
Left,
Up,
Right,
Down,
};
enum class BottomOSKIndex {
LowerCase,
UpperCase,
NumberPad,
};
/**
* Moves and resizes the window to a specified position and size.
*
* @param pos Top-left window position
* @param size Window size
*/
void MoveAndResizeWindow(QPoint pos, QSize size);
/**
* Rescales all keyboard elements to account for High DPI displays.
*
* @param width Window width
* @param height Window height
* @param dpi_scale Display scaling factor
*/
void RescaleKeyboardElements(float width, float height, float dpi_scale);
/// Sets the keyboard type based on initialize_parameters.
void SetKeyboardType();
/// Sets the password mode based on initialize_parameters.
void SetPasswordMode();
/// Sets the text draw type based on initialize_parameters.
void SetTextDrawType();
/// Sets the controller image at the bottom left of the software keyboard.
void SetControllerImage();
/// Disables buttons based on initialize_parameters.
void DisableKeyboardButtons();
/// Changes whether the backspace or/and ok buttons should be enabled or disabled.
void SetBackspaceOkEnabled();
/**
* Validates the input text sent in based on the parameters in initialize_parameters.
*
* @param input_text Input text
*
* @returns True if the input text is valid, false otherwise.
*/
bool ValidateInputText(const QString& input_text);
/// Switches between LowerCase and UpperCase (Shift and Caps Lock)
void ChangeBottomOSKIndex();
/// Processes a keyboard button click from the UI as normal keyboard input.
void NormalKeyboardButtonClicked(QPushButton* button);
/// Processes a keyboard button click from the UI as inline keyboard input.
void InlineKeyboardButtonClicked(QPushButton* button);
/**
* Inserts a string of arbitrary length into the current_text at the current cursor position.
* This is only used for the inline software keyboard.
*/
void InlineTextInsertString(std::u16string_view string);
/// Setup the mouse hover workaround for "focusing" buttons. This should only be called once.
void SetupMouseHover();
/**
* Handles button presses and converts them into keyboard input.
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
void HandleButtonPressedOnce();
/**
* Handles button holds and converts them into keyboard input.
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
void HandleButtonHold();
/**
* Translates a button press to focus or click a keyboard button.
*
* @param button The button press to process.
*/
void TranslateButtonPress(HIDButton button);
/**
* Moves the focus of a button in a certain direction.
*
* @param direction The direction to move.
*/
void MoveButtonDirection(Direction direction);
/**
* Moves the text cursor in a certain direction.
*
* @param direction The direction to move.
*/
void MoveTextCursorDirection(Direction direction);
void StartInputThread();
void StopInputThread();
/// The thread where input is being polled and processed.
void InputThread();
std::unique_ptr<Ui::QtSoftwareKeyboardDialog> ui;
Core::System& system;
// True if it is the inline software keyboard.
bool is_inline;
// Common software keyboard initialize parameters.
Core::Frontend::KeyboardInitializeParameters initialize_parameters;
// Used only by the inline software keyboard since the QLineEdit or QTextEdit is hidden.
std::u16string current_text;
s32 cursor_position{0};
static constexpr std::size_t NUM_ROWS_NORMAL = 5;
static constexpr std::size_t NUM_COLUMNS_NORMAL = 12;
static constexpr std::size_t NUM_ROWS_NUMPAD = 4;
static constexpr std::size_t NUM_COLUMNS_NUMPAD = 4;
// Stores the normal keyboard layout.
std::array<std::array<std::array<QPushButton*, NUM_COLUMNS_NORMAL>, NUM_ROWS_NORMAL>, 2>
keyboard_buttons;
// Stores the numberpad keyboard layout.
std::array<std::array<QPushButton*, NUM_COLUMNS_NUMPAD>, NUM_ROWS_NUMPAD> numberpad_buttons;
// Contains a set of all buttons used in keyboard_buttons and numberpad_buttons.
std::array<QPushButton*, 110> all_buttons;
std::size_t row{0};
std::size_t column{0};
BottomOSKIndex bottom_osk_index{BottomOSKIndex::LowerCase};
std::atomic<bool> caps_lock_enabled{false};
std::unique_ptr<InputInterpreter> input_interpreter;
std::thread input_thread;
std::atomic<bool> input_thread_running{};
};
class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet {
Q_OBJECT
public:
explicit QtSoftwareKeyboard(GMainWindow& parent);
~QtSoftwareKeyboard() override;
void InitializeKeyboard(
bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback_) override;
void ShowNormalKeyboard() const override;
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const override;
void ShowInlineKeyboard(
Core::Frontend::InlineAppearParameters appear_parameters) const override;
void HideInlineKeyboard() const override;
void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override;
void ExitKeyboard() const override;
signals:
void MainWindowInitializeKeyboard(
bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) const;
void MainWindowShowNormalKeyboard() const;
void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const;
void MainWindowShowInlineKeyboard(
Core::Frontend::InlineAppearParameters appear_parameters) const;
void MainWindowHideInlineKeyboard() const;
void MainWindowInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const;
void MainWindowExitKeyboard() const;
private:
void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
std::u16string submitted_text) const;
void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
std::u16string submitted_text, s32 cursor_position) const;
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
submit_normal_callback;
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback;
};
File diff suppressed because it is too large Load Diff
-417
View File
@@ -1,417 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#ifdef YUZU_USE_QT_WEB_ENGINE
#include <QKeyEvent>
#include <QWebEngineProfile>
#include <QWebEngineScript>
#include <QWebEngineScriptCollection>
#include <QWebEngineSettings>
#include <QWebEngineUrlScheme>
#endif
#include "common/fs/path_util.h"
#include "core/core.h"
#include "core/frontend/input_interpreter.h"
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "yuzu/applets/web_browser.h"
#include "yuzu/applets/web_browser_scripts.h"
#include "yuzu/main.h"
#include "yuzu/util/url_request_interceptor.h"
#ifdef YUZU_USE_QT_WEB_ENGINE
namespace {
constexpr int HIDButtonToKey(HIDButton button) {
switch (button) {
case HIDButton::DLeft:
case HIDButton::LStickLeft:
return Qt::Key_Left;
case HIDButton::DUp:
case HIDButton::LStickUp:
return Qt::Key_Up;
case HIDButton::DRight:
case HIDButton::LStickRight:
return Qt::Key_Right;
case HIDButton::DDown:
case HIDButton::LStickDown:
return Qt::Key_Down;
default:
return 0;
}
}
} // Anonymous namespace
QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system,
InputCommon::InputSubsystem* input_subsystem_)
: QWebEngineView(parent), input_subsystem{input_subsystem_},
url_interceptor(std::make_unique<UrlRequestInterceptor>()),
input_interpreter(std::make_unique<InputInterpreter>(system)),
default_profile{QWebEngineProfile::defaultProfile()},
global_settings{QWebEngineSettings::globalSettings()} {
QWebEngineScript gamepad;
QWebEngineScript window_nx;
gamepad.setName(QStringLiteral("gamepad_script.js"));
window_nx.setName(QStringLiteral("window_nx_script.js"));
gamepad.setSourceCode(QString::fromStdString(GAMEPAD_SCRIPT));
window_nx.setSourceCode(QString::fromStdString(WINDOW_NX_SCRIPT));
gamepad.setInjectionPoint(QWebEngineScript::DocumentCreation);
window_nx.setInjectionPoint(QWebEngineScript::DocumentCreation);
gamepad.setWorldId(QWebEngineScript::MainWorld);
window_nx.setWorldId(QWebEngineScript::MainWorld);
gamepad.setRunsOnSubFrames(true);
window_nx.setRunsOnSubFrames(true);
default_profile->scripts()->insert(gamepad);
default_profile->scripts()->insert(window_nx);
default_profile->setRequestInterceptor(url_interceptor.get());
global_settings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
global_settings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
global_settings->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true);
global_settings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
global_settings->setAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript, true);
global_settings->setAttribute(QWebEngineSettings::ShowScrollBars, false);
global_settings->setFontFamily(QWebEngineSettings::StandardFont, QStringLiteral("Roboto"));
connect(
page(), &QWebEnginePage::windowCloseRequested, page(),
[this] {
if (page()->url() == url_interceptor->GetRequestedURL()) {
SetFinished(true);
SetExitReason(Service::AM::Applets::WebExitReason::WindowClosed);
}
},
Qt::QueuedConnection);
}
QtNXWebEngineView::~QtNXWebEngineView() {
SetFinished(true);
StopInputThread();
}
void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url,
const std::string& additional_args) {
is_local = true;
LoadExtractedFonts();
SetUserAgent(UserAgent::WebApplet);
SetFinished(false);
SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed);
SetLastURL("http://localhost/");
StartInputThread();
load(QUrl(QUrl::fromLocalFile(QString::fromStdString(main_url)).toString() +
QString::fromStdString(additional_args)));
}
void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url,
const std::string& additional_args) {
is_local = false;
SetUserAgent(UserAgent::WebApplet);
SetFinished(false);
SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed);
SetLastURL("http://localhost/");
StartInputThread();
load(QUrl(QString::fromStdString(main_url) + QString::fromStdString(additional_args)));
}
void QtNXWebEngineView::SetUserAgent(UserAgent user_agent) {
const QString user_agent_str = [user_agent] {
switch (user_agent) {
case UserAgent::WebApplet:
default:
return QStringLiteral("WebApplet");
case UserAgent::ShopN:
return QStringLiteral("ShopN");
case UserAgent::LoginApplet:
return QStringLiteral("LoginApplet");
case UserAgent::ShareApplet:
return QStringLiteral("ShareApplet");
case UserAgent::LobbyApplet:
return QStringLiteral("LobbyApplet");
case UserAgent::WifiWebAuthApplet:
return QStringLiteral("WifiWebAuthApplet");
}
}();
QWebEngineProfile::defaultProfile()->setHttpUserAgent(
QStringLiteral("Mozilla/5.0 (Nintendo Switch; %1) AppleWebKit/606.4 "
"(KHTML, like Gecko) NF/6.0.1.15.4 NintendoBrowser/5.1.0.20389")
.arg(user_agent_str));
}
bool QtNXWebEngineView::IsFinished() const {
return finished;
}
void QtNXWebEngineView::SetFinished(bool finished_) {
finished = finished_;
}
Service::AM::Applets::WebExitReason QtNXWebEngineView::GetExitReason() const {
return exit_reason;
}
void QtNXWebEngineView::SetExitReason(Service::AM::Applets::WebExitReason exit_reason_) {
exit_reason = exit_reason_;
}
const std::string& QtNXWebEngineView::GetLastURL() const {
return last_url;
}
void QtNXWebEngineView::SetLastURL(std::string last_url_) {
last_url = std::move(last_url_);
}
QString QtNXWebEngineView::GetCurrentURL() const {
return url_interceptor->GetRequestedURL().toString();
}
void QtNXWebEngineView::hide() {
SetFinished(true);
StopInputThread();
QWidget::hide();
}
void QtNXWebEngineView::keyPressEvent(QKeyEvent* event) {
if (is_local) {
input_subsystem->GetKeyboard()->PressKey(event->key());
}
}
void QtNXWebEngineView::keyReleaseEvent(QKeyEvent* event) {
if (is_local) {
input_subsystem->GetKeyboard()->ReleaseKey(event->key());
}
}
template <HIDButton... T>
void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
const auto f = [this](HIDButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) {
page()->runJavaScript(
QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)),
[&](const QVariant& variant) {
if (variant.toBool()) {
switch (button) {
case HIDButton::A:
SendMultipleKeyPressEvents<Qt::Key_A, Qt::Key_Space, Qt::Key_Return>();
break;
case HIDButton::B:
SendKeyPressEvent(Qt::Key_B);
break;
case HIDButton::X:
SendKeyPressEvent(Qt::Key_X);
break;
case HIDButton::Y:
SendKeyPressEvent(Qt::Key_Y);
break;
default:
break;
}
}
});
page()->runJavaScript(
QStringLiteral("if (yuzu_key_callbacks[%1] != null) { yuzu_key_callbacks[%1](); }")
.arg(static_cast<u8>(button)));
}
};
(f(T), ...);
}
template <HIDButton... T>
void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() {
const auto f = [this](HIDButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) {
SendKeyPressEvent(HIDButtonToKey(button));
}
};
(f(T), ...);
}
template <HIDButton... T>
void QtNXWebEngineView::HandleWindowKeyButtonHold() {
const auto f = [this](HIDButton button) {
if (input_interpreter->IsButtonHeld(button)) {
SendKeyPressEvent(HIDButtonToKey(button));
}
};
(f(T), ...);
}
void QtNXWebEngineView::SendKeyPressEvent(int key) {
if (key == 0) {
return;
}
QCoreApplication::postEvent(focusProxy(),
new QKeyEvent(QKeyEvent::KeyPress, key, Qt::NoModifier));
QCoreApplication::postEvent(focusProxy(),
new QKeyEvent(QKeyEvent::KeyRelease, key, Qt::NoModifier));
}
void QtNXWebEngineView::StartInputThread() {
if (input_thread_running) {
return;
}
input_thread_running = true;
input_thread = std::thread(&QtNXWebEngineView::InputThread, this);
}
void QtNXWebEngineView::StopInputThread() {
if (is_local) {
QWidget::releaseKeyboard();
}
input_thread_running = false;
if (input_thread.joinable()) {
input_thread.join();
}
}
void QtNXWebEngineView::InputThread() {
// Wait for 1 second before allowing any inputs to be processed.
std::this_thread::sleep_for(std::chrono::seconds(1));
if (is_local) {
QWidget::grabKeyboard();
}
while (input_thread_running) {
input_interpreter->PollInput();
HandleWindowFooterButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::X, HIDButton::Y,
HIDButton::L, HIDButton::R>();
HandleWindowKeyButtonPressedOnce<HIDButton::DLeft, HIDButton::DUp, HIDButton::DRight,
HIDButton::DDown, HIDButton::LStickLeft,
HIDButton::LStickUp, HIDButton::LStickRight,
HIDButton::LStickDown>();
HandleWindowKeyButtonHold<HIDButton::DLeft, HIDButton::DUp, HIDButton::DRight,
HIDButton::DDown, HIDButton::LStickLeft, HIDButton::LStickUp,
HIDButton::LStickRight, HIDButton::LStickDown>();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
void QtNXWebEngineView::LoadExtractedFonts() {
QWebEngineScript nx_font_css;
QWebEngineScript load_nx_font;
auto fonts_dir_str = Common::FS::PathToUTF8String(
Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts/");
std::replace(fonts_dir_str.begin(), fonts_dir_str.end(), '\\', '/');
const auto fonts_dir = QString::fromStdString(fonts_dir_str);
nx_font_css.setName(QStringLiteral("nx_font_css.js"));
load_nx_font.setName(QStringLiteral("load_nx_font.js"));
nx_font_css.setSourceCode(
QString::fromStdString(NX_FONT_CSS)
.arg(fonts_dir + QStringLiteral("FontStandard.ttf"))
.arg(fonts_dir + QStringLiteral("FontChineseSimplified.ttf"))
.arg(fonts_dir + QStringLiteral("FontExtendedChineseSimplified.ttf"))
.arg(fonts_dir + QStringLiteral("FontChineseTraditional.ttf"))
.arg(fonts_dir + QStringLiteral("FontKorean.ttf"))
.arg(fonts_dir + QStringLiteral("FontNintendoExtended.ttf"))
.arg(fonts_dir + QStringLiteral("FontNintendoExtended2.ttf")));
load_nx_font.setSourceCode(QString::fromStdString(LOAD_NX_FONT));
nx_font_css.setInjectionPoint(QWebEngineScript::DocumentReady);
load_nx_font.setInjectionPoint(QWebEngineScript::Deferred);
nx_font_css.setWorldId(QWebEngineScript::MainWorld);
load_nx_font.setWorldId(QWebEngineScript::MainWorld);
nx_font_css.setRunsOnSubFrames(true);
load_nx_font.setRunsOnSubFrames(true);
default_profile->scripts()->insert(nx_font_css);
default_profile->scripts()->insert(load_nx_font);
connect(
url_interceptor.get(), &UrlRequestInterceptor::FrameChanged, url_interceptor.get(),
[this] {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
page()->runJavaScript(QString::fromStdString(LOAD_NX_FONT));
},
Qt::QueuedConnection);
}
#endif
QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
connect(this, &QtWebBrowser::MainWindowOpenWebPage, &main_window,
&GMainWindow::WebBrowserOpenWebPage, Qt::QueuedConnection);
connect(&main_window, &GMainWindow::WebBrowserExtractOfflineRomFS, this,
&QtWebBrowser::MainWindowExtractOfflineRomFS, Qt::QueuedConnection);
connect(&main_window, &GMainWindow::WebBrowserClosed, this,
&QtWebBrowser::MainWindowWebBrowserClosed, Qt::QueuedConnection);
}
QtWebBrowser::~QtWebBrowser() = default;
void QtWebBrowser::OpenLocalWebPage(
const std::string& local_url, std::function<void()> extract_romfs_callback_,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const {
extract_romfs_callback = std::move(extract_romfs_callback_);
callback = std::move(callback_);
const auto index = local_url.find('?');
if (index == std::string::npos) {
emit MainWindowOpenWebPage(local_url, "", true);
} else {
emit MainWindowOpenWebPage(local_url.substr(0, index), local_url.substr(index), true);
}
}
void QtWebBrowser::OpenExternalWebPage(
const std::string& external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback_) const {
callback = std::move(callback_);
const auto index = external_url.find('?');
if (index == std::string::npos) {
emit MainWindowOpenWebPage(external_url, "", false);
} else {
emit MainWindowOpenWebPage(external_url.substr(0, index), external_url.substr(index),
false);
}
}
void QtWebBrowser::MainWindowExtractOfflineRomFS() {
extract_romfs_callback();
}
void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason,
std::string last_url) {
callback(exit_reason, last_url);
}
-218
View File
@@ -1,218 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <atomic>
#include <memory>
#include <thread>
#include <QObject>
#ifdef YUZU_USE_QT_WEB_ENGINE
#include <QWebEngineView>
#endif
#include "core/frontend/applets/web_browser.h"
enum class HIDButton : u8;
class GMainWindow;
class InputInterpreter;
class UrlRequestInterceptor;
namespace Core {
class System;
}
namespace InputCommon {
class InputSubsystem;
}
#ifdef YUZU_USE_QT_WEB_ENGINE
enum class UserAgent {
WebApplet,
ShopN,
LoginApplet,
ShareApplet,
LobbyApplet,
WifiWebAuthApplet,
};
class QWebEngineProfile;
class QWebEngineSettings;
class QtNXWebEngineView : public QWebEngineView {
Q_OBJECT
public:
explicit QtNXWebEngineView(QWidget* parent, Core::System& system,
InputCommon::InputSubsystem* input_subsystem_);
~QtNXWebEngineView() override;
/**
* Loads a HTML document that exists locally. Cannot be used to load external websites.
*
* @param main_url The url to the file.
* @param additional_args Additional arguments appended to the main url.
*/
void LoadLocalWebPage(const std::string& main_url, const std::string& additional_args);
/**
* Loads an external website. Cannot be used to load local urls.
*
* @param main_url The url to the website.
* @param additional_args Additional arguments appended to the main url.
*/
void LoadExternalWebPage(const std::string& main_url, const std::string& additional_args);
/**
* Sets the background color of the web page.
*
* @param color The color to set.
*/
void SetBackgroundColor(QColor color);
/**
* Sets the user agent of the web browser.
*
* @param user_agent The user agent enum.
*/
void SetUserAgent(UserAgent user_agent);
[[nodiscard]] bool IsFinished() const;
void SetFinished(bool finished_);
[[nodiscard]] Service::AM::Applets::WebExitReason GetExitReason() const;
void SetExitReason(Service::AM::Applets::WebExitReason exit_reason_);
[[nodiscard]] const std::string& GetLastURL() const;
void SetLastURL(std::string last_url_);
/**
* This gets the current URL that has been requested by the webpage.
* This only applies to the main frame. Sub frames and other resources are ignored.
*
* @return Currently requested URL
*/
[[nodiscard]] QString GetCurrentURL() const;
public slots:
void hide();
protected:
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
private:
/**
* Handles button presses to execute functions assigned in yuzu_key_callbacks.
* yuzu_key_callbacks contains specialized functions for the buttons in the window footer
* that can be overriden by games to achieve desired functionality.
*
* @tparam HIDButton The list of buttons contained in yuzu_key_callbacks
*/
template <HIDButton... T>
void HandleWindowFooterButtonPressedOnce();
/**
* Handles button presses and converts them into keyboard input.
* This should only be used to convert D-Pad or Analog Stick input into arrow keys.
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
void HandleWindowKeyButtonPressedOnce();
/**
* Handles button holds and converts them into keyboard input.
* This should only be used to convert D-Pad or Analog Stick input into arrow keys.
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
void HandleWindowKeyButtonHold();
/**
* Sends a key press event to QWebEngineView.
*
* @param key Qt key code.
*/
void SendKeyPressEvent(int key);
/**
* Sends multiple key press events to QWebEngineView.
*
* @tparam int Qt key code.
*/
template <int... T>
void SendMultipleKeyPressEvents() {
(SendKeyPressEvent(T), ...);
}
void StartInputThread();
void StopInputThread();
/// The thread where input is being polled and processed.
void InputThread();
/// Loads the extracted fonts using JavaScript.
void LoadExtractedFonts();
InputCommon::InputSubsystem* input_subsystem;
std::unique_ptr<UrlRequestInterceptor> url_interceptor;
std::unique_ptr<InputInterpreter> input_interpreter;
std::thread input_thread;
std::atomic<bool> input_thread_running{};
std::atomic<bool> finished{};
Service::AM::Applets::WebExitReason exit_reason{
Service::AM::Applets::WebExitReason::EndButtonPressed};
std::string last_url{"http://localhost/"};
bool is_local{};
QWebEngineProfile* default_profile;
QWebEngineSettings* global_settings;
};
#endif
class QtWebBrowser final : public QObject, public Core::Frontend::WebBrowserApplet {
Q_OBJECT
public:
explicit QtWebBrowser(GMainWindow& parent);
~QtWebBrowser() override;
void OpenLocalWebPage(const std::string& local_url,
std::function<void()> extract_romfs_callback_,
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
callback_) const override;
void OpenExternalWebPage(const std::string& external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
callback_) const override;
signals:
void MainWindowOpenWebPage(const std::string& main_url, const std::string& additional_args,
bool is_local) const;
private:
void MainWindowExtractOfflineRomFS();
void MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason,
std::string last_url);
mutable std::function<void()> extract_romfs_callback;
mutable std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback;
};
-193
View File
@@ -1,193 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
constexpr char NX_FONT_CSS[] = R"(
(function() {
css = document.createElement('style');
css.type = 'text/css';
css.id = 'nx_font';
css.innerText = `
/* FontStandard */
@font-face {
font-family: 'FontStandard';
src: url('%1') format('truetype');
}
/* FontChineseSimplified */
@font-face {
font-family: 'FontChineseSimplified';
src: url('%2') format('truetype');
}
/* FontExtendedChineseSimplified */
@font-face {
font-family: 'FontExtendedChineseSimplified';
src: url('%3') format('truetype');
}
/* FontChineseTraditional */
@font-face {
font-family: 'FontChineseTraditional';
src: url('%4') format('truetype');
}
/* FontKorean */
@font-face {
font-family: 'FontKorean';
src: url('%5') format('truetype');
}
/* FontNintendoExtended */
@font-face {
font-family: 'NintendoExt003';
src: url('%6') format('truetype');
}
/* FontNintendoExtended2 */
@font-face {
font-family: 'NintendoExt003';
src: url('%7') format('truetype');
}
`;
document.head.appendChild(css);
})();
)";
constexpr char LOAD_NX_FONT[] = R"(
(function() {
var elements = document.querySelectorAll("*");
for (var i = 0; i < elements.length; i++) {
var style = window.getComputedStyle(elements[i], null);
if (style.fontFamily.includes("Arial") || style.fontFamily.includes("Calibri") ||
style.fontFamily.includes("Century") || style.fontFamily.includes("Times New Roman")) {
elements[i].style.fontFamily = "FontStandard, FontChineseSimplified, FontExtendedChineseSimplified, FontChineseTraditional, FontKorean, NintendoExt003";
} else {
elements[i].style.fontFamily = style.fontFamily + ", FontStandard, FontChineseSimplified, FontExtendedChineseSimplified, FontChineseTraditional, FontKorean, NintendoExt003";
}
}
})();
)";
constexpr char GAMEPAD_SCRIPT[] = R"(
window.addEventListener("gamepadconnected", function(e) {
console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.",
e.gamepad.index, e.gamepad.id, e.gamepad.buttons.length, e.gamepad.axes.length);
});
window.addEventListener("gamepaddisconnected", function(e) {
console.log("Gamepad disconnected from index %d: %s", e.gamepad.index, e.gamepad.id);
});
)";
constexpr char WINDOW_NX_SCRIPT[] = R"(
var end_applet = false;
var yuzu_key_callbacks = [];
(function() {
class WindowNX {
constructor() {
yuzu_key_callbacks[1] = function() { window.history.back(); };
yuzu_key_callbacks[2] = function() { window.nx.endApplet(); };
}
addEventListener(type, listener, options) {
console.log("nx.addEventListener called, type=%s", type);
window.addEventListener(type, listener, options);
}
endApplet() {
console.log("nx.endApplet called");
end_applet = true;
}
playSystemSe(system_se) {
console.log("nx.playSystemSe is not implemented, system_se=%s", system_se);
}
sendMessage(message) {
console.log("nx.sendMessage is not implemented, message=%s", message);
}
setCursorScrollSpeed(scroll_speed) {
console.log("nx.setCursorScrollSpeed is not implemented, scroll_speed=%d", scroll_speed);
}
}
class WindowNXFooter {
setAssign(key, label, func, option) {
console.log("nx.footer.setAssign called, key=%s", key);
switch (key) {
case "A":
yuzu_key_callbacks[0] = func;
break;
case "B":
yuzu_key_callbacks[1] = func;
break;
case "X":
yuzu_key_callbacks[2] = func;
break;
case "Y":
yuzu_key_callbacks[3] = func;
break;
case "L":
yuzu_key_callbacks[6] = func;
break;
case "R":
yuzu_key_callbacks[7] = func;
break;
}
}
setFixed(kind) {
console.log("nx.footer.setFixed is not implemented, kind=%s", kind);
}
unsetAssign(key) {
console.log("nx.footer.unsetAssign called, key=%s", key);
switch (key) {
case "A":
yuzu_key_callbacks[0] = function() {};
break;
case "B":
yuzu_key_callbacks[1] = function() {};
break;
case "X":
yuzu_key_callbacks[2] = function() {};
break;
case "Y":
yuzu_key_callbacks[3] = function() {};
break;
case "L":
yuzu_key_callbacks[6] = function() {};
break;
case "R":
yuzu_key_callbacks[7] = function() {};
break;
}
}
}
class WindowNXPlayReport {
incrementCounter(counter_id) {
console.log("nx.playReport.incrementCounter is not implemented, counter_id=%d", counter_id);
}
setCounterSetIdentifier(counter_id) {
console.log("nx.playReport.setCounterSetIdentifier is not implemented, counter_id=%d", counter_id);
}
}
window.nx = new WindowNX();
window.nx.footer = new WindowNXFooter();
window.nx.playReport = new WindowNXPlayReport();
})();
)";