early-access version 2486

main
pineappleEA 2022-02-10 19:04:38 +01:00
parent 5eb091f7cf
commit 3ba25dc6f2
14 changed files with 1126 additions and 401 deletions

View File

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 2485. This is the source code for early-access 2486.
## Legal Notice ## Legal Notice

View File

@ -885,6 +885,12 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
return SetVibration(device_index, DEFAULT_VIBRATION_VALUE); return SetVibration(device_index, DEFAULT_VIBRATION_VALUE);
} }
bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) {
LOG_INFO(Service_HID, "Set polling mode {}", polling_mode);
auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)];
return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None;
}
void EmulatedController::SetLedPattern() { void EmulatedController::SetLedPattern() {
for (auto& device : output_devices) { for (auto& device : output_devices) {
if (!device) { if (!device) {

View File

@ -299,16 +299,23 @@ public:
/** /**
* Sends a specific vibration to the output device * Sends a specific vibration to the output device
* @return returns true if vibration had no errors * @return true if vibration had no errors
*/ */
bool SetVibration(std::size_t device_index, VibrationValue vibration); bool SetVibration(std::size_t device_index, VibrationValue vibration);
/** /**
* Sends a small vibration to the output device * Sends a small vibration to the output device
* @return returns true if SetVibration was successfull * @return true if SetVibration was successfull
*/ */
bool TestVibration(std::size_t device_index); bool TestVibration(std::size_t device_index);
/**
* Sets the desired data to be polled from a controller
* @param polling_mode type of input desired buttons, gyro, nfc, ir, etc.
* @return true if SetPollingMode was successfull
*/
bool SetPollingMode(Common::Input::PollingMode polling_mode);
/// Returns the led pattern corresponding to this emulated controller /// Returns the led pattern corresponding to this emulated controller
LedPattern GetLedPattern() const; LedPattern GetLedPattern() const;

File diff suppressed because it is too large Load Diff

View File

@ -7,15 +7,132 @@
#include <array> #include <array>
#include <vector> #include <vector>
#include "common/common_funcs.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Kernel { namespace Kernel {
class KEvent; class KEvent;
} class KReadableEvent;
} // namespace Kernel
namespace Core::HID {
enum class NpadIdType : u32;
} // namespace Core::HID
namespace Service::NFP { namespace Service::NFP {
enum class ServiceType : u32 {
User,
Debug,
System,
};
enum class State : u32 {
NonInitialized,
Initialized,
};
enum class DeviceState : u32 {
Initialized,
SearchingForTag,
TagFound,
TagRemoved,
TagMounted,
Unaviable,
Finalized,
};
enum class ModelType : u32 {
Amiibo,
};
enum class MountTarget : u32 {
Rom,
Ram,
All,
};
enum class AmiiboType : u8 {
Figure,
Card,
Yarn,
};
enum class AmiiboSeries : u8 {
SuperSmashBros,
SuperMario,
ChibiRobo,
YoshiWoollyWorld,
Splatoon,
AnimalCrossing,
EightBitMario,
Skylanders,
Unknown8,
TheLegendOfZelda,
ShovelKnight,
Unknown11,
Kiby,
Pokemon,
MarioSportsSuperstars,
MonsterHunter,
BoxBoy,
Pikmin,
FireEmblem,
Metroid,
Others,
MegaMan,
Diablo
};
using TagUuid = std::array<u8, 10>;
struct TagInfo {
TagUuid uuid;
u8 uuid_length;
INSERT_PADDING_BYTES(0x15);
s32 protocol;
u32 tag_type;
INSERT_PADDING_BYTES(0x30);
};
static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size");
struct CommonInfo {
u16 last_write_year;
u8 last_write_month;
u8 last_write_day;
u16 write_counter;
u16 version;
u32 application_area_size;
INSERT_PADDING_BYTES(0x34);
};
static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
struct ModelInfo {
u16 character_id;
u8 character_variant;
AmiiboType amiibo_type;
u16 model_number;
AmiiboSeries series;
u8 fixed; // Must be 02
INSERT_PADDING_BYTES(0x4); // Unknown
INSERT_PADDING_BYTES(0x20); // Probably a SHA256-(HMAC?) hash
INSERT_PADDING_BYTES(0x14); // SHA256-HMAC
};
static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
struct RegisterInfo {
Service::Mii::MiiInfo mii_char_info;
u16 first_write_year;
u8 first_write_month;
u8 first_write_day;
std::array<u8, 11> amiibo_name;
u8 unknown;
INSERT_PADDING_BYTES(0x98);
};
static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size");
class Module final { class Module final {
public: public:
class Interface : public ServiceFramework<Interface> { class Interface : public ServiceFramework<Interface> {
@ -24,34 +141,126 @@ public:
const char* name); const char* name);
~Interface() override; ~Interface() override;
struct ModelInfo { struct EncryptedAmiiboFile {
std::array<u8, 0x8> amiibo_identification_block; u16 crypto_init; // Must be A5 XX
INSERT_PADDING_BYTES(0x38); u16 write_count; // Number of times the amiibo has been written?
INSERT_PADDING_BYTES(0x20); // System crypts
INSERT_PADDING_BYTES(0x20); // SHA256-(HMAC?) hash
ModelInfo model_info; // This struct is bigger than documentation
INSERT_PADDING_BYTES(0xC); // SHA256-HMAC
INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer
INSERT_PADDING_BYTES(0x54); // section 2 encrypted buffer
}; };
static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size");
struct AmiiboFile { struct NTAG215File {
std::array<u8, 10> uuid; TagUuid uuid; // Unique serial number
INSERT_PADDING_BYTES(0x4a); u16 lock_bytes; // Set defined pages as read only
ModelInfo model_info; u32 compability_container; // Defines available memory
EncryptedAmiiboFile user_memory; // Writable data
u32 dynamic_lock; // Dynamic lock
u32 CFG0; // Defines memory protected by password
u32 CFG1; // Defines number of verification attempts
u32 PWD; // Password to allow write access
u16 PACK; // Password acknowledge reply
u16 RFUI; // Reserved for future use
}; };
static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); static_assert(sizeof(NTAG215File) == 0x21C, "NTAG215File is an invalid size");
void CreateUserInterface(Kernel::HLERequestContext& ctx); void CreateUserInterface(Kernel::HLERequestContext& ctx);
bool LoadAmiibo(const std::vector<u8>& buffer); bool LoadAmiibo(const std::vector<u8>& buffer);
Kernel::KReadableEvent& GetNFCEvent(); void CloseAmiibo();
const AmiiboFile& GetAmiiboBuffer() const;
void Initialize();
void Finalize();
ResultCode StartDetection(s32 protocol_);
ResultCode StopDetection();
ResultCode Mount();
ResultCode Unmount();
ResultCode GetTagInfo(TagInfo& tag_info) const;
ResultCode GetCommonInfo(CommonInfo& common_info) const;
ResultCode GetModelInfo(ModelInfo& model_info) const;
ResultCode GetRegisterInfo(RegisterInfo& register_info) const;
ResultCode OpenApplicationArea(u32 access_id);
ResultCode GetApplicationArea(std::vector<u8>& data) const;
ResultCode SetApplicationArea(const std::vector<u8>& data);
ResultCode CreateApplicationArea(u32 access_id, const std::vector<u8>& data);
u64 GetHandle() const;
DeviceState GetCurrentState() const;
Core::HID::NpadIdType GetNpadId() const;
Kernel::KReadableEvent& GetActivateEvent() const;
Kernel::KReadableEvent& GetDeactivateEvent() const;
protected: protected:
std::shared_ptr<Module> module; std::shared_ptr<Module> module;
private: private:
/// Validates that the amiibo file is not corrupted
bool IsAmiiboValid() const;
bool AmiiboApplicationDataExist(u32 access_id) const;
std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const;
void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const;
/// return password needed to allow write access to protected memory
u32 GetTagPassword(const TagUuid& uuid) const;
const Core::HID::NpadIdType npad_id;
DeviceState device_state{DeviceState::Unaviable};
KernelHelpers::ServiceContext service_context; KernelHelpers::ServiceContext service_context;
Kernel::KEvent* nfc_tag_load; Kernel::KEvent* activate_event;
AmiiboFile amiibo{}; Kernel::KEvent* deactivate_event;
NTAG215File tag_data{};
s32 protocol;
bool is_application_area_initialized{};
u32 application_area_id;
std::vector<u8> application_area_data;
}; };
}; };
class IUser final : public ServiceFramework<IUser> {
public:
explicit IUser(Module::Interface& nfp_interface_, Core::System& system_);
private:
void Initialize(Kernel::HLERequestContext& ctx);
void Finalize(Kernel::HLERequestContext& ctx);
void ListDevices(Kernel::HLERequestContext& ctx);
void StartDetection(Kernel::HLERequestContext& ctx);
void StopDetection(Kernel::HLERequestContext& ctx);
void Mount(Kernel::HLERequestContext& ctx);
void Unmount(Kernel::HLERequestContext& ctx);
void OpenApplicationArea(Kernel::HLERequestContext& ctx);
void GetApplicationArea(Kernel::HLERequestContext& ctx);
void SetApplicationArea(Kernel::HLERequestContext& ctx);
void CreateApplicationArea(Kernel::HLERequestContext& ctx);
void GetTagInfo(Kernel::HLERequestContext& ctx);
void GetRegisterInfo(Kernel::HLERequestContext& ctx);
void GetCommonInfo(Kernel::HLERequestContext& ctx);
void GetModelInfo(Kernel::HLERequestContext& ctx);
void AttachActivateEvent(Kernel::HLERequestContext& ctx);
void AttachDeactivateEvent(Kernel::HLERequestContext& ctx);
void GetState(Kernel::HLERequestContext& ctx);
void GetDeviceState(Kernel::HLERequestContext& ctx);
void GetNpadId(Kernel::HLERequestContext& ctx);
void GetApplicationAreaSize(Kernel::HLERequestContext& ctx);
void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx);
KernelHelpers::ServiceContext service_context;
// TODO(german77): We should have a vector of interfaces
Module::Interface& nfp_interface;
State state{State::NonInitialized};
Kernel::KEvent* availability_change_event;
};
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
} // namespace Service::NFP } // namespace Service::NFP

View File

@ -369,7 +369,7 @@ template <bool has_blacklists>
void TextureCache<P>::FillImageViews(DescriptorTable<TICEntry>& table, void TextureCache<P>::FillImageViews(DescriptorTable<TICEntry>& table,
std::span<ImageViewId> cached_image_view_ids, std::span<ImageViewId> cached_image_view_ids,
std::span<ImageViewInOut> views) { std::span<ImageViewInOut> views) {
bool has_blacklisted = false; bool has_blacklisted;
do { do {
has_deleted_images = false; has_deleted_images = false;
if constexpr (has_blacklists) { if constexpr (has_blacklists) {
@ -1763,7 +1763,7 @@ void TextureCache<P>::SynchronizeAliases(ImageId image_id) {
}); });
const auto& resolution = Settings::values.resolution_info; const auto& resolution = Settings::values.resolution_info;
for (const AliasedImage* const aliased : aliased_images) { for (const AliasedImage* const aliased : aliased_images) {
if (!resolution.active || !any_rescaled) { if (!resolution.active | !any_rescaled) {
CopyImage(image_id, aliased->id, aliased->copies); CopyImage(image_id, aliased->id, aliased->copies);
continue; continue;
} }
@ -1774,7 +1774,19 @@ void TextureCache<P>::SynchronizeAliases(ImageId image_id) {
continue; continue;
} }
ScaleUp(aliased_image); ScaleUp(aliased_image);
CopyImage(image_id, aliased->id, aliased->copies);
const bool both_2d{image.info.type == ImageType::e2D &&
aliased_image.info.type == ImageType::e2D};
auto copies = aliased->copies;
for (auto copy : copies) {
copy.extent.width = std::max<u32>(
(copy.extent.width * resolution.up_scale) >> resolution.down_shift, 1);
if (both_2d) {
copy.extent.height = std::max<u32>(
(copy.extent.height * resolution.up_scale) >> resolution.down_shift, 1);
}
}
CopyImage(image_id, aliased->id, copies);
} }
} }

View File

@ -70,23 +70,25 @@ const std::array<int, 2> Config::default_ringcon_analogs{{
// This must be in alphabetical order according to action name as it must have the same order as // This must be in alphabetical order according to action name as it must have the same order as
// UISetting::values.shortcuts, which is alphabetically ordered. // UISetting::values.shortcuts, which is alphabetically ordered.
// clang-format off // clang-format off
const std::array<UISettings::Shortcut, 20> Config::default_hotkeys{{ const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{
{QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, {QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}},
{QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, {QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}},
{QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, {QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}},
{QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, {QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Change Adapting Filter"), QStringLiteral("Main Window"), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}},
{QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, {QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}},
{QStringLiteral("Change GPU Accuracy"), QStringLiteral("Main Window"), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut}},
{QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}}, {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}},
{QStringLiteral("Exit Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("Exit Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Exit yuzu"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}}, {QStringLiteral("Exit yuzu"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}},
{QStringLiteral("Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}}, {QStringLiteral("Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}},
{QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}}, {QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Load/Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}},
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("TAS Start/Stop"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("TAS Reset"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("TAS Record"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut}}, {QStringLiteral("TAS Record"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("TAS Reset"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("TAS Start/Stop"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}},
{QStringLiteral("Toggle Framerate Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Framerate Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}},
{QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}},
@ -790,6 +792,7 @@ void Config::ReadUIValues() {
ReadBasicSetting(UISettings::values.callout_flags); ReadBasicSetting(UISettings::values.callout_flags);
ReadBasicSetting(UISettings::values.show_console); ReadBasicSetting(UISettings::values.show_console);
ReadBasicSetting(UISettings::values.pause_when_in_background); ReadBasicSetting(UISettings::values.pause_when_in_background);
ReadBasicSetting(UISettings::values.mute_when_in_background);
ReadBasicSetting(UISettings::values.hide_mouse); ReadBasicSetting(UISettings::values.hide_mouse);
qt_config->endGroup(); qt_config->endGroup();
@ -1329,6 +1332,7 @@ void Config::SaveUIValues() {
WriteBasicSetting(UISettings::values.callout_flags); WriteBasicSetting(UISettings::values.callout_flags);
WriteBasicSetting(UISettings::values.show_console); WriteBasicSetting(UISettings::values.show_console);
WriteBasicSetting(UISettings::values.pause_when_in_background); WriteBasicSetting(UISettings::values.pause_when_in_background);
WriteBasicSetting(UISettings::values.mute_when_in_background);
WriteBasicSetting(UISettings::values.hide_mouse); WriteBasicSetting(UISettings::values.hide_mouse);
qt_config->endGroup(); qt_config->endGroup();

View File

@ -47,7 +47,7 @@ public:
default_mouse_buttons; default_mouse_buttons;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
static const std::array<UISettings::Shortcut, 20> default_hotkeys; static const std::array<UISettings::Shortcut, 22> default_hotkeys;
static constexpr UISettings::Theme default_theme{ static constexpr UISettings::Theme default_theme{
#ifdef _WIN32 #ifdef _WIN32

View File

@ -46,6 +46,7 @@ void ConfigureGeneral::SetConfiguration() {
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue()); ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue());
ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue()); ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue());
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue()); ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
ui->toggle_background_mute->setChecked(UISettings::values.mute_when_in_background.GetValue());
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue()); ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue()); ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue());
@ -95,6 +96,7 @@ void ConfigureGeneral::ApplyConfiguration() {
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked();
UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked();
UISettings::values.mute_when_in_background = ui->toggle_background_mute->isChecked();
UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked(); UISettings::values.hide_mouse = ui->toggle_hide_mouse->isChecked();
Settings::values.fps_cap.SetValue(ui->fps_cap->value()); Settings::values.fps_cap.SetValue(ui->fps_cap->value());

View File

@ -163,6 +163,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="toggle_background_mute">
<property name="text">
<string>Mute audio when in background</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="toggle_hide_mouse"> <widget class="QCheckBox" name="toggle_hide_mouse">
<property name="text"> <property name="text">

View File

@ -806,21 +806,8 @@ void GMainWindow::InitializeWidgets() {
filter_status_button = new QPushButton(); filter_status_button = new QPushButton();
filter_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); filter_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
filter_status_button->setFocusPolicy(Qt::NoFocus); filter_status_button->setFocusPolicy(Qt::NoFocus);
connect(filter_status_button, &QPushButton::clicked, [&] { connect(filter_status_button, &QPushButton::clicked, this,
auto filter = Settings::values.scaling_filter.GetValue(); &GMainWindow::OnToggleAdaptingFilter);
if (filter == Settings::ScalingFilter::LastFilter) {
filter = Settings::ScalingFilter::NearestNeighbor;
} else {
filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1);
}
if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL &&
filter == Settings::ScalingFilter::Fsr) {
filter = Settings::ScalingFilter::NearestNeighbor;
}
Settings::values.scaling_filter.SetValue(filter);
filter_status_button->setChecked(true);
UpdateFilterText();
});
auto filter = Settings::values.scaling_filter.GetValue(); auto filter = Settings::values.scaling_filter.GetValue();
if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL &&
filter == Settings::ScalingFilter::Fsr) { filter == Settings::ScalingFilter::Fsr) {
@ -835,25 +822,7 @@ void GMainWindow::InitializeWidgets() {
dock_status_button = new QPushButton(); dock_status_button = new QPushButton();
dock_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); dock_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
dock_status_button->setFocusPolicy(Qt::NoFocus); dock_status_button->setFocusPolicy(Qt::NoFocus);
connect(dock_status_button, &QPushButton::clicked, [&] { connect(dock_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleDockedMode);
const bool is_docked = Settings::values.use_docked_mode.GetValue();
auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (!is_docked && handheld->IsConnected()) {
QMessageBox::warning(this, tr("Invalid config detected"),
tr("Handheld controller can't be used on docked mode. Pro "
"controller will be selected."));
handheld->Disconnect();
player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
player_1->Connect();
controller_dialog->refreshConfiguration();
}
Settings::values.use_docked_mode.SetValue(!is_docked);
dock_status_button->setChecked(!is_docked);
OnDockedModeChanged(is_docked, !is_docked, *system);
});
dock_status_button->setText(tr("DOCK")); dock_status_button->setText(tr("DOCK"));
dock_status_button->setCheckable(true); dock_status_button->setCheckable(true);
dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
@ -863,22 +832,7 @@ void GMainWindow::InitializeWidgets() {
gpu_accuracy_button->setObjectName(QStringLiteral("GPUStatusBarButton")); gpu_accuracy_button->setObjectName(QStringLiteral("GPUStatusBarButton"));
gpu_accuracy_button->setCheckable(true); gpu_accuracy_button->setCheckable(true);
gpu_accuracy_button->setFocusPolicy(Qt::NoFocus); gpu_accuracy_button->setFocusPolicy(Qt::NoFocus);
connect(gpu_accuracy_button, &QPushButton::clicked, [this] { connect(gpu_accuracy_button, &QPushButton::clicked, this, &GMainWindow::OnToggleGpuAccuracy);
switch (Settings::values.gpu_accuracy.GetValue()) {
case Settings::GPUAccuracy::High: {
Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::Normal);
break;
}
case Settings::GPUAccuracy::Normal:
case Settings::GPUAccuracy::Extreme:
default: {
Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High);
}
}
system->ApplySettings();
UpdateGPUAccuracyButton();
});
UpdateGPUAccuracyButton(); UpdateGPUAccuracyButton();
statusBar()->insertPermanentWidget(0, gpu_accuracy_button); statusBar()->insertPermanentWidget(0, gpu_accuracy_button);
@ -980,7 +934,7 @@ void GMainWindow::InitializeHotkeys() {
hotkey_registry.LoadHotkeys(); hotkey_registry.LoadHotkeys();
LinkActionShortcut(ui->action_Load_File, QStringLiteral("Load File")); LinkActionShortcut(ui->action_Load_File, QStringLiteral("Load File"));
LinkActionShortcut(ui->action_Load_Amiibo, QStringLiteral("Load Amiibo")); LinkActionShortcut(ui->action_Load_Amiibo, QStringLiteral("Load/Remove Amiibo"));
LinkActionShortcut(ui->action_Exit, QStringLiteral("Exit yuzu")); LinkActionShortcut(ui->action_Exit, QStringLiteral("Exit yuzu"));
LinkActionShortcut(ui->action_Restart, QStringLiteral("Restart Emulation")); LinkActionShortcut(ui->action_Restart, QStringLiteral("Restart Emulation"));
LinkActionShortcut(ui->action_Pause, QStringLiteral("Continue/Pause Emulation")); LinkActionShortcut(ui->action_Pause, QStringLiteral("Continue/Pause Emulation"));
@ -1009,12 +963,10 @@ void GMainWindow::InitializeHotkeys() {
ToggleFullscreen(); ToggleFullscreen();
} }
}); });
connect_shortcut(QStringLiteral("Change Docked Mode"), [&] { connect_shortcut(QStringLiteral("Change Adapting Filter"),
Settings::values.use_docked_mode.SetValue(!Settings::values.use_docked_mode.GetValue()); &GMainWindow::OnToggleAdaptingFilter);
OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(), connect_shortcut(QStringLiteral("Change Docked Mode"), &GMainWindow::OnToggleDockedMode);
Settings::values.use_docked_mode.GetValue(), *system); connect_shortcut(QStringLiteral("Change GPU Accuracy"), &GMainWindow::OnToggleGpuAccuracy);
dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
});
connect_shortcut(QStringLiteral("Audio Mute/Unmute"), connect_shortcut(QStringLiteral("Audio Mute/Unmute"),
[] { Settings::values.audio_muted = !Settings::values.audio_muted; }); [] { Settings::values.audio_muted = !Settings::values.audio_muted; });
connect_shortcut(QStringLiteral("Audio Volume Down"), [] { connect_shortcut(QStringLiteral("Audio Volume Down"), [] {
@ -1082,14 +1034,14 @@ void GMainWindow::RestoreUIState() {
} }
void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) { void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
if (!UISettings::values.pause_when_in_background) {
return;
}
if (state != Qt::ApplicationHidden && state != Qt::ApplicationInactive && if (state != Qt::ApplicationHidden && state != Qt::ApplicationInactive &&
state != Qt::ApplicationActive) { state != Qt::ApplicationActive) {
LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state); LOG_DEBUG(Frontend, "ApplicationState unusual flag: {} ", state);
} }
if (emulation_running) { if (!emulation_running) {
return;
}
if (UISettings::values.pause_when_in_background) {
if (emu_thread->IsRunning() && if (emu_thread->IsRunning() &&
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) { (state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
auto_paused = true; auto_paused = true;
@ -1099,6 +1051,16 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
OnStartGame(); OnStartGame();
} }
} }
if (UISettings::values.mute_when_in_background) {
if (!Settings::values.audio_muted &&
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
Settings::values.audio_muted = true;
auto_muted = true;
} else if (auto_muted && state == Qt::ApplicationActive) {
Settings::values.audio_muted = false;
auto_muted = false;
}
}
} }
void GMainWindow::ConnectWidgetEvents() { void GMainWindow::ConnectWidgetEvents() {
@ -2868,6 +2830,59 @@ void GMainWindow::OnTasReset() {
input_subsystem->GetTas()->Reset(); input_subsystem->GetTas()->Reset();
} }
void GMainWindow::OnToggleDockedMode() {
const bool is_docked = Settings::values.use_docked_mode.GetValue();
auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (!is_docked && handheld->IsConnected()) {
QMessageBox::warning(this, tr("Invalid config detected"),
tr("Handheld controller can't be used on docked mode. Pro "
"controller will be selected."));
handheld->Disconnect();
player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
player_1->Connect();
controller_dialog->refreshConfiguration();
}
Settings::values.use_docked_mode.SetValue(!is_docked);
dock_status_button->setChecked(!is_docked);
OnDockedModeChanged(is_docked, !is_docked, *system);
}
void GMainWindow::OnToggleGpuAccuracy() {
switch (Settings::values.gpu_accuracy.GetValue()) {
case Settings::GPUAccuracy::High: {
Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::Normal);
break;
}
case Settings::GPUAccuracy::Normal:
case Settings::GPUAccuracy::Extreme:
default: {
Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High);
}
}
system->ApplySettings();
UpdateGPUAccuracyButton();
}
void GMainWindow::OnToggleAdaptingFilter() {
auto filter = Settings::values.scaling_filter.GetValue();
if (filter == Settings::ScalingFilter::LastFilter) {
filter = Settings::ScalingFilter::NearestNeighbor;
} else {
filter = static_cast<Settings::ScalingFilter>(static_cast<u32>(filter) + 1);
}
if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL &&
filter == Settings::ScalingFilter::Fsr) {
filter = Settings::ScalingFilter::NearestNeighbor;
}
Settings::values.scaling_filter.SetValue(filter);
filter_status_button->setChecked(true);
UpdateFilterText();
}
void GMainWindow::OnConfigurePerGame() { void GMainWindow::OnConfigurePerGame() {
const u64 title_id = system->GetCurrentProcessProgramID(); const u64 title_id = system->GetCurrentProcessProgramID();
OpenPerGameConfiguration(title_id, game_path.toStdString()); OpenPerGameConfiguration(title_id, game_path.toStdString());
@ -2912,6 +2927,24 @@ void GMainWindow::OnLoadAmiibo() {
return; return;
} }
Service::SM::ServiceManager& sm = system->ServiceManager();
auto nfc = sm.GetService<Service::NFP::Module::Interface>("nfp:user");
if (nfc == nullptr) {
QMessageBox::warning(this, tr("Error"), tr("The current game is not looking for amiibos"));
return;
}
const auto nfc_state = nfc->GetCurrentState();
if (nfc_state == Service::NFP::DeviceState::TagFound ||
nfc_state == Service::NFP::DeviceState::TagMounted) {
nfc->CloseAmiibo();
return;
}
if (nfc_state != Service::NFP::DeviceState::SearchingForTag) {
QMessageBox::warning(this, tr("Error"), tr("The current game is not looking for amiibos"));
return;
}
is_amiibo_file_select_active = true; is_amiibo_file_select_active = true;
const QString extensions{QStringLiteral("*.bin")}; const QString extensions{QStringLiteral("*.bin")};
const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions); const QString file_filter = tr("Amiibo File (%1);; All Files (*.*)").arg(extensions);

View File

@ -284,6 +284,9 @@ private slots:
void OnTasStartStop(); void OnTasStartStop();
void OnTasRecord(); void OnTasRecord();
void OnTasReset(); void OnTasReset();
void OnToggleDockedMode();
void OnToggleGpuAccuracy();
void OnToggleAdaptingFilter();
void OnConfigurePerGame(); void OnConfigurePerGame();
void OnLoadAmiibo(); void OnLoadAmiibo();
void OnOpenYuzuFolder(); void OnOpenYuzuFolder();
@ -369,6 +372,7 @@ private:
QString game_path; QString game_path;
bool auto_paused = false; bool auto_paused = false;
bool auto_muted = false;
QTimer mouse_hide_timer; QTimer mouse_hide_timer;
// FS // FS

View File

@ -266,7 +266,7 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Load &amp;Amiibo...</string> <string>Load/Remove &amp;Amiibo...</string>
</property> </property>
</action> </action>
<action name="action_Report_Compatibility"> <action name="action_Report_Compatibility">

View File

@ -73,6 +73,7 @@ struct Values {
Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"}; Settings::BasicSetting<bool> confirm_before_closing{true, "confirmClose"};
Settings::BasicSetting<bool> first_start{true, "firstStart"}; Settings::BasicSetting<bool> first_start{true, "firstStart"};
Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"};
Settings::BasicSetting<bool> mute_when_in_background{false, "muteWhenInBackground"};
Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"}; Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"};
Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"}; Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"};