diff options
Diffstat (limited to '')
121 files changed, 5357 insertions, 5593 deletions
diff --git a/.gitmodules b/.gitmodules index b72a2ec8c..45dd0d259 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "enet"] path = externals/enet url = https://github.com/lsalzman/enet.git -[submodule "inih"] - path = externals/inih/inih - url = https://github.com/benhoyt/inih.git [submodule "cubeb"] path = externals/cubeb url = https://github.com/mozilla/cubeb.git @@ -61,3 +58,6 @@ [submodule "breakpad"] path = externals/breakpad url = https://github.com/yuzu-emu/breakpad.git +[submodule "simpleini"] + path = externals/simpleini + url = https://github.com/brofield/simpleini.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c35e0946..e5cac8fe9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,7 +285,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) find_package(Boost 1.79.0 REQUIRED context) find_package(enet 1.3 MODULE) find_package(fmt 9 REQUIRED) -find_package(inih 52 MODULE COMPONENTS INIReader) find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle) find_package(lz4 REQUIRED) find_package(nlohmann_json 3.8 REQUIRED) diff --git a/CMakeModules/Findinih.cmake b/CMakeModules/Findinih.cmake deleted file mode 100644 index 791befebd..000000000 --- a/CMakeModules/Findinih.cmake +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf> -# -# SPDX-License-Identifier: GPL-3.0-or-later - -find_package(PkgConfig QUIET) -pkg_search_module(INIH QUIET IMPORTED_TARGET inih) -if (INIReader IN_LIST inih_FIND_COMPONENTS) - pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader) - if (INIREADER_FOUND) - set(inih_INIReader_FOUND TRUE) - endif() -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(inih - REQUIRED_VARS INIH_LINK_LIBRARIES - VERSION_VAR INIH_VERSION - HANDLE_COMPONENTS -) - -if (inih_FOUND AND NOT TARGET inih::inih) - add_library(inih::inih ALIAS PkgConfig::INIH) -endif() - -if (inih_FOUND AND inih_INIReader_FOUND AND NOT TARGET inih::INIReader) - add_library(inih::INIReader ALIAS PkgConfig::INIREADER) -endif() diff --git a/dist/languages/.tx/config b/dist/languages/.tx/config index 30e76b925..cca7b3d67 100644 --- a/dist/languages/.tx/config +++ b/dist/languages/.tx/config @@ -6,3 +6,8 @@ file_filter = <lang>.ts source_file = en.ts source_lang = en type = QT + +[o:yuzu-emulator:p:yuzu:r:yuzu-android] +file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml +source_file = ../../src/android/app/src/main/res/values/strings.xml +type = ANDROID diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index be8b0b5e8..515e3f2a4 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -34,11 +34,6 @@ endif() # Glad add_subdirectory(glad) -# inih -if (NOT TARGET inih::INIReader) - add_subdirectory(inih) -endif() - # mbedtls add_subdirectory(mbedtls) target_include_directories(mbedtls PUBLIC ./mbedtls/include) @@ -295,3 +290,6 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client) target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB) endif() endif() + +# SimpleIni +add_subdirectory(simpleini) diff --git a/externals/inih/CMakeLists.txt b/externals/inih/CMakeLists.txt deleted file mode 100644 index ebb60a976..000000000 --- a/externals/inih/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-FileCopyrightText: 2014 Gui Andrade <admin@archshift.com> -# SPDX-License-Identifier: GPL-2.0-or-later - -add_library(inih - inih/ini.c - inih/ini.h - inih/cpp/INIReader.cpp - inih/cpp/INIReader.h -) - -create_target_directory_groups(inih) -target_include_directories(inih INTERFACE inih/cpp) -add_library(inih::INIReader ALIAS inih) diff --git a/externals/inih/inih b/externals/inih/inih deleted file mode 160000 -Subproject 9cecf0643da0846e77f64d10a126d9f48b9e05e diff --git a/externals/simpleini b/externals/simpleini new file mode 160000 +Subproject 382ddbb4b92c0b26aa1b32cefba2002119a5b1f diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2ca4904a..e04d2418b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -187,6 +187,7 @@ add_subdirectory(audio_core) add_subdirectory(video_core) add_subdirectory(network) add_subdirectory(input_common) +add_subdirectory(frontend_common) add_subdirectory(shader_recompiler) if (YUZU_ROOM) diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 021b070e0..5721327e7 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -219,7 +219,6 @@ dependencies { implementation("io.coil-kt:coil:2.2.2") implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.window:window:1.2.0-beta03") - implementation("org.ini4j:ini4j:0.5.4") implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") implementation("androidx.navigation:navigation-fragment-ktx:2.7.4") diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 9ebd6c732..f2ba2504c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -230,8 +230,6 @@ object NativeLibrary { */ external fun onTouchReleased(finger_id: Int) - external fun reloadSettings() - external fun initGameIni(gameID: String?) external fun setAppDirectory(directory: String) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index 2bf0e1b0d..d005c656e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt @@ -7,7 +7,7 @@ import android.text.TextUtils import android.widget.Toast import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication -import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile +import org.yuzu.yuzu_emu.utils.NativeConfig object Settings { private val context get() = YuzuApplication.appContext @@ -19,7 +19,7 @@ object Settings { context.getString(R.string.ini_saved), Toast.LENGTH_SHORT ).show() - SettingsFile.saveFile(SettingsFile.FILE_NAME_CONFIG) + NativeConfig.saveSettings() } else { // TODO: Save custom game settings Toast.makeText( diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt index c73edd50e..48bdbdd75 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt @@ -21,7 +21,6 @@ import androidx.navigation.navArgs import com.google.android.material.color.MaterialColors import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -import org.yuzu.yuzu_emu.NativeLibrary import java.io.IOException import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding @@ -165,11 +164,12 @@ class SettingsActivity : AppCompatActivity() { settingsViewModel.shouldSave = false // Delete settings file because the user may have changed values that do not exist in the UI + NativeConfig.unloadConfig() val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG) if (!settingsFile.delete()) { throw IOException("Failed to delete $settingsFile") } - NativeLibrary.reloadSettings() + NativeConfig.initializeConfig() Toast.makeText( applicationContext, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt index 2b04d666a..3ae5b4653 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt @@ -3,15 +3,8 @@ package org.yuzu.yuzu_emu.features.settings.utils -import android.widget.Toast import java.io.* -import org.ini4j.Wini -import org.yuzu.yuzu_emu.R -import org.yuzu.yuzu_emu.YuzuApplication -import org.yuzu.yuzu_emu.features.settings.model.* import org.yuzu.yuzu_emu.utils.DirectoryInitialization -import org.yuzu.yuzu_emu.utils.Log -import org.yuzu.yuzu_emu.utils.NativeConfig /** * Contains static methods for interacting with .ini files in which settings are stored. @@ -19,41 +12,6 @@ import org.yuzu.yuzu_emu.utils.NativeConfig object SettingsFile { const val FILE_NAME_CONFIG = "config" - /** - * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error - * telling why it failed. - * - * @param fileName The target filename without a path or extension. - */ - fun saveFile(fileName: String) { - val ini = getSettingsFile(fileName) - try { - val wini = Wini(ini) - for (specificCategory in Settings.Category.values()) { - val categoryHeader = NativeConfig.getConfigHeader(specificCategory.ordinal) - for (setting in Settings.settingsList) { - if (setting.key!!.isEmpty()) continue - - val settingCategoryHeader = - NativeConfig.getConfigHeader(setting.category.ordinal) - val iniSetting: String? = wini.get(categoryHeader, setting.key) - if (iniSetting != null || settingCategoryHeader == categoryHeader) { - wini.put(settingCategoryHeader, setting.key, setting.valueAsString) - } - } - } - wini.store() - } catch (e: IOException) { - Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.message) - val context = YuzuApplication.appContext - Toast.makeText( - context, - context.getString(R.string.error_saving, fileName, e.message), - Toast.LENGTH_SHORT - ).show() - } - } - fun getSettingsFile(fileName: String): File = File(DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini") } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index ace5dddea..bd2f4cd25 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -625,6 +625,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } // Clear existing user data + NativeConfig.unloadConfig() File(DirectoryInitialization.userDirectory!!).deleteRecursively() // Copy archive to internal storage @@ -643,6 +644,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { // Reinitialize relevant data NativeLibrary.initializeSystem(true) + NativeConfig.initializeConfig() gamesViewModel.reloadGames(false) return@newInstance getString(R.string.user_data_import_success) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt index 5e9a1176a..21270fc84 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt @@ -16,6 +16,7 @@ object DirectoryInitialization { if (!areDirectoriesReady) { initializeInternalStorage() NativeLibrary.initializeSystem(false) + NativeConfig.initializeConfig() areDirectoriesReady = true } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt index 9425f8b99..87e579fa7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt @@ -4,6 +4,30 @@ package org.yuzu.yuzu_emu.utils object NativeConfig { + /** + * Creates a Config object and opens the emulation config. + */ + @Synchronized + external fun initializeConfig() + + /** + * Destroys the stored config object. This automatically saves the existing config. + */ + @Synchronized + external fun unloadConfig() + + /** + * Reads values saved to the config file and saves them. + */ + @Synchronized + external fun reloadSettings() + + /** + * Saves settings values in memory to disk. + */ + @Synchronized + external fun saveSettings() + external fun getBoolean(key: String, getDefault: Boolean): Boolean external fun setBoolean(key: String, value: Boolean) diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 88a570f68..2acc93da8 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt @@ -6,9 +6,6 @@ add_library(yuzu-android SHARED android_common/android_common.h applets/software_keyboard.cpp applets/software_keyboard.h - config.cpp - config.h - default_ini.h emu_window/emu_window.cpp emu_window/emu_window.h id_cache.cpp @@ -16,15 +13,17 @@ add_library(yuzu-android SHARED native.cpp native.h native_config.cpp - uisettings.cpp + android_settings.cpp game_metadata.cpp native_log.cpp + android_config.cpp + android_config.h ) set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) -target_link_libraries(yuzu-android PRIVATE audio_core common core input_common) -target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics log) +target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common) +target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log) if (ARCHITECTURE_arm64) target_link_libraries(yuzu-android PRIVATE adrenotools) endif() diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp new file mode 100644 index 000000000..3041c25c9 --- /dev/null +++ b/src/android/app/src/main/jni/android_config.cpp @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "android_config.h" +#include "android_settings.h" +#include "common/settings_setting.h" + +AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_type) + : Config(config_type) { + Initialize(config_name); + if (config_type != ConfigType::InputProfile) { + ReadAndroidValues(); + SaveAndroidValues(); + } +} + +AndroidConfig::~AndroidConfig() { + if (global) { + AndroidConfig::SaveAllValues(); + } +} + +void AndroidConfig::ReloadAllValues() { + Reload(); + ReadAndroidValues(); + SaveAndroidValues(); +} + +void AndroidConfig::SaveAllValues() { + Save(); + SaveAndroidValues(); +} + +void AndroidConfig::ReadAndroidValues() { + if (global) { + ReadAndroidUIValues(); + } +} + +void AndroidConfig::ReadAndroidUIValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Android)); + + ReadCategory(Settings::Category::Android); + + EndGroup(); +} + +void AndroidConfig::SaveAndroidValues() { + if (global) { + SaveAndroidUIValues(); + } + + WriteToIni(); +} + +void AndroidConfig::SaveAndroidUIValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Android)); + + WriteCategory(Settings::Category::Android); + + EndGroup(); +} + +std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) { + auto& map = Settings::values.linkage.by_category; + if (map.contains(category)) { + return Settings::values.linkage.by_category[category]; + } + return AndroidSettings::values.linkage.by_category[category]; +} diff --git a/src/android/app/src/main/jni/android_config.h b/src/android/app/src/main/jni/android_config.h new file mode 100644 index 000000000..e679392fd --- /dev/null +++ b/src/android/app/src/main/jni/android_config.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "frontend_common/config.h" + +class AndroidConfig final : public Config { +public: + explicit AndroidConfig(const std::string& config_name = "config", + ConfigType config_type = ConfigType::GlobalConfig); + ~AndroidConfig() override; + + void ReloadAllValues() override; + void SaveAllValues() override; + +protected: + void ReadAndroidValues(); + void ReadAndroidUIValues(); + void ReadHidbusValues() override {} + void ReadDebugControlValues() override {} + void ReadPathValues() override {} + void ReadShortcutValues() override {} + void ReadUIValues() override {} + void ReadUIGamelistValues() override {} + void ReadUILayoutValues() override {} + void ReadMultiplayerValues() override {} + + void SaveAndroidValues(); + void SaveAndroidUIValues(); + void SaveHidbusValues() override {} + void SaveDebugControlValues() override {} + void SavePathValues() override {} + void SaveShortcutValues() override {} + void SaveUIValues() override {} + void SaveUIGamelistValues() override {} + void SaveUILayoutValues() override {} + void SaveMultiplayerValues() override {} + + std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override; +}; diff --git a/src/android/app/src/main/jni/uisettings.cpp b/src/android/app/src/main/jni/android_settings.cpp index f2f0bad50..16023a6b0 100644 --- a/src/android/app/src/main/jni/uisettings.cpp +++ b/src/android/app/src/main/jni/android_settings.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "uisettings.h" +#include "android_settings.h" namespace AndroidSettings { diff --git a/src/android/app/src/main/jni/uisettings.h b/src/android/app/src/main/jni/android_settings.h index 37bc33918..37bc33918 100644 --- a/src/android/app/src/main/jni/uisettings.h +++ b/src/android/app/src/main/jni/android_settings.h diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp deleted file mode 100644 index 81120ab0f..000000000 --- a/src/android/app/src/main/jni/config.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <memory> -#include <optional> -#include <sstream> - -#include <INIReader.h> -#include "common/fs/file.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "common/settings_enums.h" -#include "core/hle/service/acc/profile_manager.h" -#include "input_common/main.h" -#include "jni/config.h" -#include "jni/default_ini.h" -#include "uisettings.h" - -namespace FS = Common::FS; - -Config::Config(const std::string& config_name, ConfigType config_type) - : type(config_type), global{config_type == ConfigType::GlobalConfig} { - Initialize(config_name); -} - -Config::~Config() = default; - -bool Config::LoadINI(const std::string& default_contents, bool retry) { - void(FS::CreateParentDir(config_loc)); - config = std::make_unique<INIReader>(FS::PathToUTF8String(config_loc)); - const auto config_loc_str = FS::PathToUTF8String(config_loc); - if (config->ParseError() < 0) { - if (retry) { - LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", - config_loc_str); - - void(FS::CreateParentDir(config_loc)); - void(FS::WriteStringToFile(config_loc, FS::FileType::TextFile, default_contents)); - - config = std::make_unique<INIReader>(config_loc_str); - - return LoadINI(default_contents, false); - } - LOG_ERROR(Config, "Failed."); - return false; - } - LOG_INFO(Config, "Successfully loaded {}", config_loc_str); - return true; -} - -template <> -void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) { - std::string setting_value = config->Get(group, setting.GetLabel(), setting.GetDefault()); - if (setting_value.empty()) { - setting_value = setting.GetDefault(); - } - setting = std::move(setting_value); -} - -template <> -void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) { - setting = config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); -} - -template <typename Type, bool ranged> -void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) { - setting = static_cast<Type>( - config->GetInteger(group, setting.GetLabel(), static_cast<long>(setting.GetDefault()))); -} - -void Config::ReadValues() { - ReadSetting("ControlsGeneral", Settings::values.mouse_enabled); - ReadSetting("ControlsGeneral", Settings::values.touch_device); - ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled); - ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled); - ReadSetting("ControlsGeneral", Settings::values.vibration_enabled); - ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations); - ReadSetting("ControlsGeneral", Settings::values.motion_enabled); - Settings::values.touchscreen.enabled = - config->GetBoolean("ControlsGeneral", "touch_enabled", true); - Settings::values.touchscreen.rotation_angle = - config->GetInteger("ControlsGeneral", "touch_angle", 0); - Settings::values.touchscreen.diameter_x = - config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); - Settings::values.touchscreen.diameter_y = - config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); - - int num_touch_from_button_maps = - config->GetInteger("ControlsGeneral", "touch_from_button_map", 0); - if (num_touch_from_button_maps > 0) { - for (int i = 0; i < num_touch_from_button_maps; ++i) { - Settings::TouchFromButtonMap map; - map.name = config->Get("ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + - std::string("_name"), - "default"); - const int num_touch_maps = config->GetInteger( - "ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"), - 0); - map.buttons.reserve(num_touch_maps); - - for (int j = 0; j < num_touch_maps; ++j) { - std::string touch_mapping = - config->Get("ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + - std::string("_bind_") + std::to_string(j), - ""); - map.buttons.emplace_back(std::move(touch_mapping)); - } - - Settings::values.touch_from_button_maps.emplace_back(std::move(map)); - } - } else { - Settings::values.touch_from_button_maps.emplace_back( - Settings::TouchFromButtonMap{"default", {}}); - num_touch_from_button_maps = 1; - } - Settings::values.touch_from_button_map_index = std::clamp( - Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); - - ReadSetting("ControlsGeneral", Settings::values.udp_input_servers); - - // Data Storage - ReadSetting("Data Storage", Settings::values.use_virtual_sd); - FS::SetYuzuPath(FS::YuzuPath::NANDDir, - config->Get("Data Storage", "nand_directory", - FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); - FS::SetYuzuPath(FS::YuzuPath::SDMCDir, - config->Get("Data Storage", "sdmc_directory", - FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); - FS::SetYuzuPath(FS::YuzuPath::LoadDir, - config->Get("Data Storage", "load_directory", - FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); - FS::SetYuzuPath(FS::YuzuPath::DumpDir, - config->Get("Data Storage", "dump_directory", - FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); - ReadSetting("Data Storage", Settings::values.gamecard_inserted); - ReadSetting("Data Storage", Settings::values.gamecard_current_game); - ReadSetting("Data Storage", Settings::values.gamecard_path); - - // System - ReadSetting("System", Settings::values.current_user); - Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0, - Service::Account::MAX_USERS - 1); - - // Disable docked mode by default on Android - Settings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false) - ? Settings::ConsoleMode::Docked - : Settings::ConsoleMode::Handheld); - - const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false); - if (rng_seed_enabled) { - Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0)); - } else { - Settings::values.rng_seed.SetValue(0); - } - Settings::values.rng_seed_enabled.SetValue(rng_seed_enabled); - - const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false); - if (custom_rtc_enabled) { - Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0); - } else { - Settings::values.custom_rtc = 0; - } - Settings::values.custom_rtc_enabled = custom_rtc_enabled; - - ReadSetting("System", Settings::values.language_index); - ReadSetting("System", Settings::values.region_index); - ReadSetting("System", Settings::values.time_zone_index); - ReadSetting("System", Settings::values.sound_index); - - // Core - ReadSetting("Core", Settings::values.use_multi_core); - ReadSetting("Core", Settings::values.memory_layout_mode); - - // Cpu - ReadSetting("Cpu", Settings::values.cpu_accuracy); - ReadSetting("Cpu", Settings::values.cpu_debug_mode); - ReadSetting("Cpu", Settings::values.cpuopt_page_tables); - ReadSetting("Cpu", Settings::values.cpuopt_block_linking); - ReadSetting("Cpu", Settings::values.cpuopt_return_stack_buffer); - ReadSetting("Cpu", Settings::values.cpuopt_fast_dispatcher); - ReadSetting("Cpu", Settings::values.cpuopt_context_elimination); - ReadSetting("Cpu", Settings::values.cpuopt_const_prop); - ReadSetting("Cpu", Settings::values.cpuopt_misc_ir); - ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks); - ReadSetting("Cpu", Settings::values.cpuopt_fastmem); - ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives); - ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives); - ReadSetting("Cpu", Settings::values.cpuopt_ignore_memory_aborts); - ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma); - ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error); - ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr); - ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan); - ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check); - ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor); - - // Renderer - ReadSetting("Renderer", Settings::values.renderer_backend); - ReadSetting("Renderer", Settings::values.renderer_debug); - ReadSetting("Renderer", Settings::values.renderer_shader_feedback); - ReadSetting("Renderer", Settings::values.enable_nsight_aftermath); - ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks); - ReadSetting("Renderer", Settings::values.vulkan_device); - - ReadSetting("Renderer", Settings::values.resolution_setup); - ReadSetting("Renderer", Settings::values.scaling_filter); - ReadSetting("Renderer", Settings::values.fsr_sharpening_slider); - ReadSetting("Renderer", Settings::values.anti_aliasing); - ReadSetting("Renderer", Settings::values.fullscreen_mode); - ReadSetting("Renderer", Settings::values.aspect_ratio); - ReadSetting("Renderer", Settings::values.max_anisotropy); - ReadSetting("Renderer", Settings::values.use_speed_limit); - ReadSetting("Renderer", Settings::values.speed_limit); - ReadSetting("Renderer", Settings::values.use_disk_shader_cache); - ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); - ReadSetting("Renderer", Settings::values.vsync_mode); - ReadSetting("Renderer", Settings::values.shader_backend); - ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); - ReadSetting("Renderer", Settings::values.nvdec_emulation); - ReadSetting("Renderer", Settings::values.use_fast_gpu_time); - ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache); - - ReadSetting("Renderer", Settings::values.bg_red); - ReadSetting("Renderer", Settings::values.bg_green); - ReadSetting("Renderer", Settings::values.bg_blue); - - // Use GPU accuracy normal by default on Android - Settings::values.gpu_accuracy = static_cast<Settings::GpuAccuracy>(config->GetInteger( - "Renderer", "gpu_accuracy", static_cast<u32>(Settings::GpuAccuracy::Normal))); - - // Use GPU default anisotropic filtering on Android - Settings::values.max_anisotropy = - static_cast<Settings::AnisotropyMode>(config->GetInteger("Renderer", "max_anisotropy", 1)); - - // Disable ASTC compute by default on Android - Settings::values.accelerate_astc.SetValue( - config->GetBoolean("Renderer", "accelerate_astc", false) ? Settings::AstcDecodeMode::Gpu - : Settings::AstcDecodeMode::Cpu); - - // Enable asynchronous presentation by default on Android - Settings::values.async_presentation = - config->GetBoolean("Renderer", "async_presentation", true); - - // Disable force_max_clock by default on Android - Settings::values.renderer_force_max_clock = - config->GetBoolean("Renderer", "force_max_clock", false); - - // Disable use_reactive_flushing by default on Android - Settings::values.use_reactive_flushing = - config->GetBoolean("Renderer", "use_reactive_flushing", false); - - // Audio - ReadSetting("Audio", Settings::values.sink_id); - ReadSetting("Audio", Settings::values.audio_output_device_id); - ReadSetting("Audio", Settings::values.volume); - - // Miscellaneous - // log_filter has a different default here than from common - Settings::values.log_filter = "*:Info"; - ReadSetting("Miscellaneous", Settings::values.use_dev_keys); - - // Debugging - Settings::values.record_frame_times = - config->GetBoolean("Debugging", "record_frame_times", false); - ReadSetting("Debugging", Settings::values.dump_exefs); - ReadSetting("Debugging", Settings::values.dump_nso); - ReadSetting("Debugging", Settings::values.enable_fs_access_log); - ReadSetting("Debugging", Settings::values.reporting_services); - ReadSetting("Debugging", Settings::values.quest_flag); - ReadSetting("Debugging", Settings::values.use_debug_asserts); - ReadSetting("Debugging", Settings::values.use_auto_stub); - ReadSetting("Debugging", Settings::values.disable_macro_jit); - ReadSetting("Debugging", Settings::values.disable_macro_hle); - ReadSetting("Debugging", Settings::values.use_gdbstub); - ReadSetting("Debugging", Settings::values.gdbstub_port); - - const auto title_list = config->Get("AddOns", "title_ids", ""); - std::stringstream ss(title_list); - std::string line; - while (std::getline(ss, line, '|')) { - const auto title_id = std::strtoul(line.c_str(), nullptr, 16); - const auto disabled_list = config->Get("AddOns", "disabled_" + line, ""); - - std::stringstream inner_ss(disabled_list); - std::string inner_line; - std::vector<std::string> out; - while (std::getline(inner_ss, inner_line, '|')) { - out.push_back(inner_line); - } - - Settings::values.disabled_addons.insert_or_assign(title_id, out); - } - - // Web Service - ReadSetting("WebService", Settings::values.enable_telemetry); - ReadSetting("WebService", Settings::values.web_api_url); - ReadSetting("WebService", Settings::values.yuzu_username); - ReadSetting("WebService", Settings::values.yuzu_token); - - // Network - ReadSetting("Network", Settings::values.network_interface); - - // Android - ReadSetting("Android", AndroidSettings::values.picture_in_picture); - ReadSetting("Android", AndroidSettings::values.screen_layout); -} - -void Config::Initialize(const std::string& config_name) { - const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); - const auto config_file = fmt::format("{}.ini", config_name); - - switch (type) { - case ConfigType::GlobalConfig: - config_loc = FS::PathToUTF8String(fs_config_loc / config_file); - break; - case ConfigType::PerGameConfig: - config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); - break; - case ConfigType::InputProfile: - config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); - LoadINI(DefaultINI::android_config_file); - return; - } - LoadINI(DefaultINI::android_config_file); - ReadValues(); -} diff --git a/src/android/app/src/main/jni/config.h b/src/android/app/src/main/jni/config.h deleted file mode 100644 index e1e8f47ed..000000000 --- a/src/android/app/src/main/jni/config.h +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <filesystem> -#include <memory> -#include <optional> -#include <string> - -#include "common/settings.h" - -class INIReader; - -class Config { - bool LoadINI(const std::string& default_contents = "", bool retry = true); - -public: - enum class ConfigType { - GlobalConfig, - PerGameConfig, - InputProfile, - }; - - explicit Config(const std::string& config_name = "config", - ConfigType config_type = ConfigType::GlobalConfig); - ~Config(); - - void Initialize(const std::string& config_name); - -private: - /** - * Applies a value read from the config to a Setting. - * - * @param group The name of the INI group - * @param setting The yuzu setting to modify - */ - template <typename Type, bool ranged> - void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting); - - void ReadValues(); - - const ConfigType type; - std::unique_ptr<INIReader> config; - std::string config_loc; - const bool global; -}; diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h deleted file mode 100644 index d81422a74..000000000 --- a/src/android/app/src/main/jni/default_ini.h +++ /dev/null @@ -1,511 +0,0 @@ -// SPDX-FileCopyrightText: 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -namespace DefaultINI { - -const char* android_config_file = R"( - -[ControlsP0] -# The input devices and parameters for each Switch native input -# The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ... -# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." -# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values - -# Indicates if this player should be connected at boot -connected= - -# for button input, the following devices are available: -# - "keyboard" (default) for keyboard input. Required parameters: -# - "code": the code of the key to bind -# - "sdl" for joystick input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "button"(optional): the index of the button to bind -# - "hat"(optional): the index of the hat to bind as direction buttons -# - "axis"(optional): the index of the axis to bind -# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" -# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is -# triggered if the axis value crosses -# - "direction"(only used for axis): "+" means the button is triggered when the axis value -# is greater than the threshold; "-" means the button is triggered when the axis value -# is smaller than the threshold -button_a= -button_b= -button_x= -button_y= -button_lstick= -button_rstick= -button_l= -button_r= -button_zl= -button_zr= -button_plus= -button_minus= -button_dleft= -button_dup= -button_dright= -button_ddown= -button_lstick_left= -button_lstick_up= -button_lstick_right= -button_lstick_down= -button_sl= -button_sr= -button_home= -button_screenshot= - -# for analog input, the following devices are available: -# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: -# - "up", "down", "left", "right": sub-devices for each direction. -# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" -# - "modifier": sub-devices as a modifier. -# - "modifier_scale": a float number representing the applied modifier scale to the analog input. -# Must be in range of 0.0-1.0. Defaults to 0.5 -# - "sdl" for joystick input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "axis_x": the index of the axis to bind as x-axis (default to 0) -# - "axis_y": the index of the axis to bind as y-axis (default to 1) -lstick= -rstick= - -# for motion input, the following devices are available: -# - "keyboard" (default) for emulating random motion input from buttons. Required parameters: -# - "code": the code of the key to bind -# - "sdl" for motion input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "motion": the index of the motion sensor to bind -# - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters: -# - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001" -# - "port": the port of the cemu hook server -# - "pad": the index of the joystick -# - "motion": the index of the motion sensor of the joystick to bind -motionleft= -motionright= - -[ControlsGeneral] -# To use the debug_pad, prepend `debug_pad_` before each button setting above. -# i.e. debug_pad_button_a= - -# Enable debug pad inputs to the guest -# 0 (default): Disabled, 1: Enabled -debug_pad_enabled = - -# Whether to enable or disable vibration -# 0: Disabled, 1 (default): Enabled -vibration_enabled= - -# Whether to enable or disable accurate vibrations -# 0 (default): Disabled, 1: Enabled -enable_accurate_vibrations= - -# Enables controller motion inputs -# 0: Disabled, 1 (default): Enabled -motion_enabled = - -# Defines the udp device's touch screen coordinate system for cemuhookudp devices -# - "min_x", "min_y", "max_x", "max_y" -touch_device= - -# for mapping buttons to touch inputs. -#touch_from_button_map=1 -#touch_from_button_maps_0_name=default -#touch_from_button_maps_0_count=2 -#touch_from_button_maps_0_bind_0=foo -#touch_from_button_maps_0_bind_1=bar -# etc. - -# List of Cemuhook UDP servers, delimited by ','. -# Default: 127.0.0.1:26760 -# Example: 127.0.0.1:26760,123.4.5.67:26761 -udp_input_servers = - -# Enable controlling an axis via a mouse input. -# 0 (default): Off, 1: On -mouse_panning = - -# Set mouse sensitivity. -# Default: 1.0 -mouse_panning_sensitivity = - -# Emulate an analog control stick from keyboard inputs. -# 0 (default): Disabled, 1: Enabled -emulate_analog_keyboard = - -# Enable mouse inputs to the guest -# 0 (default): Disabled, 1: Enabled -mouse_enabled = - -# Enable keyboard inputs to the guest -# 0 (default): Disabled, 1: Enabled -keyboard_enabled = - -[Core] -# Whether to use multi-core for CPU emulation -# 0: Disabled, 1 (default): Enabled -use_multi_core = - -# Enable unsafe extended guest system memory layout (8GB DRAM) -# 0 (default): Disabled, 1: Enabled -use_unsafe_extended_memory_layout = - -[Cpu] -# Adjusts various optimizations. -# Auto-select mode enables choice unsafe optimizations. -# Accurate enables only safe optimizations. -# Unsafe allows any unsafe optimizations. -# 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations -cpu_accuracy = - -# Allow disabling safe optimizations. -# 0 (default): Disabled, 1: Enabled -cpu_debug_mode = - -# Enable inline page tables optimization (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_page_tables = - -# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) -# 0: Disabled, 1 (default): Enabled -cpuopt_block_linking = - -# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) -# 0: Disabled, 1 (default): Enabled -cpuopt_return_stack_buffer = - -# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) -# 0: Disabled, 1 (default): Enabled -cpuopt_fast_dispatcher = - -# Enable context elimination CPU Optimization (reduce host memory use for guest context) -# 0: Disabled, 1 (default): Enabled -cpuopt_context_elimination = - -# Enable constant propagation CPU optimization (basic IR optimization) -# 0: Disabled, 1 (default): Enabled -cpuopt_const_prop = - -# Enable miscellaneous CPU optimizations (basic IR optimization) -# 0: Disabled, 1 (default): Enabled -cpuopt_misc_ir = - -# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) -# 0: Disabled, 1 (default): Enabled -cpuopt_reduce_misalign_checks = - -# Enable Host MMU Emulation (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_fastmem = - -# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_fastmem_exclusives = - -# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_recompile_exclusives = - -# Enable optimization to ignore invalid memory accesses (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_ignore_memory_aborts = - -# Enable unfuse FMA (improve performance on CPUs without FMA) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_unfuse_fma = - -# Enable faster FRSQRTE and FRECPE -# Only enabled if cpu_accuracy is set to Unsafe. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_reduce_fp_error = - -# Enable faster ASIMD instructions (32 bits only) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_ignore_standard_fpcr = - -# Enable inaccurate NaN handling -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_inaccurate_nan = - -# Disable address space checks (64 bits only) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_fastmem_check = - -# Enable faster exclusive instructions -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_ignore_global_monitor = - -[Renderer] -# Which backend API to use. -# 0: OpenGL (unsupported), 1 (default): Vulkan, 2: Null -backend = - -# Whether to enable asynchronous presentation (Vulkan only) -# 0: Off, 1 (default): On -async_presentation = - -# Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied). -# 0 (default): Disabled, 1: Enabled -force_max_clock = - -# Enable graphics API debugging mode. -# 0 (default): Disabled, 1: Enabled -debug = - -# Enable shader feedback. -# 0 (default): Disabled, 1: Enabled -renderer_shader_feedback = - -# Enable Nsight Aftermath crash dumps -# 0 (default): Disabled, 1: Enabled -nsight_aftermath = - -# Disable shader loop safety checks, executing the shader without loop logic changes -# 0 (default): Disabled, 1: Enabled -disable_shader_loop_safety_checks = - -# Which Vulkan physical device to use (defaults to 0) -vulkan_device = - -# 0: 0.5x (360p/540p) [EXPERIMENTAL] -# 1: 0.75x (540p/810p) [EXPERIMENTAL] -# 2 (default): 1x (720p/1080p) -# 3: 2x (1440p/2160p) -# 4: 3x (2160p/3240p) -# 5: 4x (2880p/4320p) -# 6: 5x (3600p/5400p) -# 7: 6x (4320p/6480p) -resolution_setup = - -# Pixel filter to use when up- or down-sampling rendered frames. -# 0: Nearest Neighbor -# 1 (default): Bilinear -# 2: Bicubic -# 3: Gaussian -# 4: ScaleForce -# 5: AMD FidelityFX™️ Super Resolution [Vulkan Only] -scaling_filter = - -# Anti-Aliasing (AA) -# 0 (default): None, 1: FXAA -anti_aliasing = - -# Whether to use fullscreen or borderless window mode -# 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen -fullscreen_mode = - -# Aspect ratio -# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window -aspect_ratio = - -# Anisotropic filtering -# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x -max_anisotropy = - -# Whether to enable VSync or not. -# OpenGL: Values other than 0 enable VSync -# Vulkan: FIFO is selected if the requested mode is not supported by the driver. -# FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. -# FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. -# Mailbox can have lower latency than FIFO and does not tear but may drop frames. -# Immediate (no synchronization) just presents whatever is available and can exhibit tearing. -# 0: Immediate (Off), 1 (Default): Mailbox (On), 2: FIFO, 3: FIFO Relaxed -use_vsync = - -# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is -# not available and GLASM is selected, GLSL will be used. -# 0: GLSL, 1 (default): GLASM, 2: SPIR-V -shader_backend = - -# Whether to allow asynchronous shader building. -# 0 (default): Off, 1: On -use_asynchronous_shaders = - -# Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory. -# 0 (default): Off, 1: On -use_reactive_flushing = - -# NVDEC emulation. -# 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding -nvdec_emulation = - -# Accelerate ASTC texture decoding. -# 0 (default): Off, 1: On -accelerate_astc = - -# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value -# 0: Off, 1: On (default) -use_speed_limit = - -# Limits the speed of the game to run no faster than this value as a percentage of target speed -# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) -speed_limit = - -# Whether to use disk based shader cache -# 0: Off, 1 (default): On -use_disk_shader_cache = - -# Which gpu accuracy level to use -# 0 (default): Normal, 1: High, 2: Extreme (Very slow) -gpu_accuracy = - -# Whether to use asynchronous GPU emulation -# 0 : Off (slow), 1 (default): On (fast) -use_asynchronous_gpu_emulation = - -# Inform the guest that GPU operations completed more quickly than they did. -# 0: Off, 1 (default): On -use_fast_gpu_time = - -# Force unmodified buffers to be flushed, which can cost performance. -# 0: Off (default), 1: On -use_pessimistic_flushes = - -# Whether to use garbage collection or not for GPU caches. -# 0 (default): Off, 1: On -use_caches_gc = - -# The clear color for the renderer. What shows up on the sides of the bottom screen. -# Must be in range of 0-255. Defaults to 0 for all. -bg_red = -bg_blue = -bg_green = - -[Audio] -# Which audio output engine to use. -# auto (default): Auto-select -# cubeb: Cubeb audio engine (if available) -# sdl2: SDL2 audio engine (if available) -# null: No audio output -output_engine = - -# Which audio device to use. -# auto (default): Auto-select -output_device = - -# Output volume. -# 100 (default): 100%, 0; mute -volume = - -[Data Storage] -# Whether to create a virtual SD card. -# 1: Yes, 0 (default): No -use_virtual_sd = - -# Whether or not to enable gamecard emulation -# 1: Yes, 0 (default): No -gamecard_inserted = - -# Whether or not the gamecard should be emulated as the current game -# If 'gamecard_inserted' is 0 this setting is irrelevant -# 1: Yes, 0 (default): No -gamecard_current_game = - -# Path to an XCI file to use as the gamecard -# If 'gamecard_inserted' is 0 this setting is irrelevant -# If 'gamecard_current_game' is 1 this setting is irrelevant -gamecard_path = - -[System] -# Whether the system is docked -# 1 (default): Yes, 0: No -use_docked_mode = - -# Sets the seed for the RNG generator built into the switch -# rng_seed will be ignored and randomly generated if rng_seed_enabled is false -rng_seed_enabled = -rng_seed = - -# Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service -# This will auto-increment, with the time set being the time the game is started -# This override will only occur if custom_rtc_enabled is true, otherwise the current time is used -custom_rtc_enabled = -custom_rtc = - -# Sets the systems language index -# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, -# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, -# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese -language_index = - -# The system region that yuzu will use during emulation -# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan -region_index = - -# The system time zone that yuzu will use during emulation -# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone -time_zone_index = - -# Sets the sound output mode. -# 0: Mono, 1 (default): Stereo, 2: Surround -sound_index = - -[Miscellaneous] -# A filter which removes logs below a certain logging level. -# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical -log_filter = *:Trace - -# Use developer keys -# 0 (default): Disabled, 1: Enabled -use_dev_keys = - -[Debugging] -# Record frame time data, can be found in the log directory. Boolean value -record_frame_times = -# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them -dump_exefs=false -# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them -dump_nso=false -# Determines whether or not yuzu will save the filesystem access log. -enable_fs_access_log=false -# Enables verbose reporting services -reporting_services = -# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode -# false: Retail/Normal Mode (default), true: Kiosk Mode -quest_flag = -# Determines whether debug asserts should be enabled, which will throw an exception on asserts. -# false: Disabled (default), true: Enabled -use_debug_asserts = -# Determines whether unimplemented HLE service calls should be automatically stubbed. -# false: Disabled (default), true: Enabled -use_auto_stub = -# Enables/Disables the macro JIT compiler -disable_macro_jit=false -# Determines whether to enable the GDB stub and wait for the debugger to attach before running. -# false: Disabled (default), true: Enabled -use_gdbstub=false -# The port to use for the GDB server, if it is enabled. -gdbstub_port=6543 - -[WebService] -# Whether or not to enable telemetry -# 0: No, 1 (default): Yes -enable_telemetry = -# URL for Web API -web_api_url = https://api.yuzu-emu.org -# Username and token for yuzu Web Service -# See https://profile.yuzu-emu.org/ for more info -yuzu_username = -yuzu_token = - -[Network] -# Name of the network interface device to use with yuzu LAN play. -# e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo' -# e.g. On Windows: 'Ethernet', 'Wi-Fi' -network_interface = - -[AddOns] -# Used to disable add-ons -# List of title IDs of games that will have add-ons disabled (separated by '|'): -title_ids = -# For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|') -# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey -)"; -} // namespace DefaultINI diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 64663b084..617288ae4 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -52,8 +52,8 @@ #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" +#include "frontend_common/config.h" #include "jni/android_common/android_common.h" -#include "jni/config.h" #include "jni/id_cache.h" #include "jni/native.h" #include "video_core/renderer_base.h" @@ -664,8 +664,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, jboolean reload) { - // Create the default config.ini. - Config{}; // Initialize the emulated system. if (!reload) { EmulationSession::GetInstance().System().Initialize(); @@ -680,17 +678,6 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass cl void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {} -void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) { - Config{}; -} - -void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz, - jstring j_game_id) { - std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); - - env->ReleaseStringUTFChars(j_game_id, game_id.data()); -} - jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) { jdoubleArray j_stats = env->NewDoubleArray(4); diff --git a/src/android/app/src/main/jni/native_config.cpp b/src/android/app/src/main/jni/native_config.cpp index 8a704960c..8e81816e5 100644 --- a/src/android/app/src/main/jni/native_config.cpp +++ b/src/android/app/src/main/jni/native_config.cpp @@ -5,11 +5,14 @@ #include <jni.h> +#include "android_config.h" +#include "android_settings.h" #include "common/logging/log.h" #include "common/settings.h" +#include "frontend_common/config.h" #include "jni/android_common/android_common.h" -#include "jni/config.h" -#include "uisettings.h" + +std::unique_ptr<AndroidConfig> config; template <typename T> Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { @@ -28,6 +31,22 @@ Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { extern "C" { +void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeConfig(JNIEnv* env, jobject obj) { + config = std::make_unique<AndroidConfig>(); +} + +void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadConfig(JNIEnv* env, jobject obj) { + config.reset(); +} + +void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadSettings(JNIEnv* env, jobject obj) { + config->AndroidConfig::ReloadAllValues(); +} + +void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveSettings(JNIEnv* env, jobject obj) { + config->AndroidConfig::SaveAllValues(); +} + jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj, jstring jkey, jboolean getDefault) { auto setting = getSetting<bool>(env, jkey); diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 51717be06..a10131eb2 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -206,9 +206,9 @@ const char* TranslateCategory(Category category) { case Category::UiAudio: return "UiAudio"; case Category::UiLayout: - return "UiLayout"; + return "UILayout"; case Category::UiGameList: - return "UiGameList"; + return "UIGameList"; case Category::Screenshots: return "Screenshots"; case Category::Shortcuts: diff --git a/src/common/settings.h b/src/common/settings.h index e899f1ae6..e75099b89 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -232,7 +232,11 @@ struct Values { SwitchableSetting<bool> use_asynchronous_gpu_emulation{ linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer}; SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage, +#ifdef ANDROID + AstcDecodeMode::Cpu, +#else AstcDecodeMode::Gpu, +#endif AstcDecodeMode::Cpu, AstcDecodeMode::CpuAsynchronous, "accelerate_astc", @@ -304,7 +308,11 @@ struct Values { linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true}; SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage, +#ifdef ANDROID + GpuAccuracy::Normal, +#else GpuAccuracy::High, +#endif GpuAccuracy::Normal, GpuAccuracy::Extreme, "gpu_accuracy", @@ -313,20 +321,38 @@ struct Values { true, true}; GpuAccuracy current_gpu_accuracy{GpuAccuracy::High}; - SwitchableSetting<AnisotropyMode, true> max_anisotropy{ - linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16, - "max_anisotropy", Category::RendererAdvanced}; + SwitchableSetting<AnisotropyMode, true> max_anisotropy{linkage, +#ifdef ANDROID + AnisotropyMode::Default, +#else + AnisotropyMode::Automatic, +#endif + AnisotropyMode::Automatic, + AnisotropyMode::X16, + "max_anisotropy", + Category::RendererAdvanced}; SwitchableSetting<AstcRecompression, true> astc_recompression{linkage, AstcRecompression::Uncompressed, AstcRecompression::Uncompressed, AstcRecompression::Bc3, "astc_recompression", Category::RendererAdvanced}; - SwitchableSetting<bool> async_presentation{linkage, false, "async_presentation", - Category::RendererAdvanced}; + SwitchableSetting<bool> async_presentation{linkage, +#ifdef ANDROID + true, +#else + false, +#endif + "async_presentation", Category::RendererAdvanced}; SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock", Category::RendererAdvanced}; - SwitchableSetting<bool> use_reactive_flushing{linkage, true, "use_reactive_flushing", + SwitchableSetting<bool> use_reactive_flushing{linkage, +#ifdef ANDROID + false, +#else + true, +#endif + "use_reactive_flushing", Category::RendererAdvanced}; SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", Category::RendererAdvanced}; @@ -390,7 +416,11 @@ struct Values { Setting<s32> current_user{linkage, 0, "current_user", Category::System}; SwitchableSetting<ConsoleMode> use_docked_mode{linkage, +#ifdef ANDROID + ConsoleMode::Handheld, +#else ConsoleMode::Docked, +#endif "use_docked_mode", Category::System, Specialization::Radio, diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 597890655..66c10fc3f 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -529,6 +529,7 @@ add_library(core STATIC hle/service/hid/hid_server.h hle/service/hid/hid_system_server.cpp hle/service/hid/hid_system_server.h + hle/service/hid/hid_util.h hle/service/hid/hidbus.cpp hle/service/hid/hidbus.h hle/service/hid/irs.cpp @@ -540,8 +541,8 @@ add_library(core STATIC hle/service/hid/xcd.cpp hle/service/hid/xcd.h hle/service/hid/errors.h - hle/service/hid/controllers/console_sixaxis.cpp - hle/service/hid/controllers/console_sixaxis.h + hle/service/hid/controllers/console_six_axis.cpp + hle/service/hid/controllers/console_six_axis.h hle/service/hid/controllers/controller_base.cpp hle/service/hid/controllers/controller_base.h hle/service/hid/controllers/debug_pad.cpp @@ -556,6 +557,10 @@ add_library(core STATIC hle/service/hid/controllers/npad.h hle/service/hid/controllers/palma.cpp hle/service/hid/controllers/palma.h + hle/service/hid/controllers/seven_six_axis.cpp + hle/service/hid/controllers/seven_six_axis.h + hle/service/hid/controllers/six_axis.cpp + hle/service/hid/controllers/six_axis.h hle/service/hid/controllers/stubbed.cpp hle/service/hid/controllers/stubbed.h hle/service/hid/controllers/touchscreen.cpp diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 34927cddd..a22015ada 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -8,6 +8,7 @@ #include "common/thread.h" #include "core/hid/emulated_controller.h" #include "core/hid/input_converter.h" +#include "core/hle/service/hid/hid_util.h" namespace Core::HID { constexpr s32 HID_JOYSTICK_MAX = 0x7fff; @@ -82,7 +83,7 @@ Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleInde } void EmulatedController::ReloadFromSettings() { - const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); const auto& player = Settings::values.players.GetValue()[player_index]; for (std::size_t index = 0; index < player.buttons.size(); ++index) { @@ -118,7 +119,7 @@ void EmulatedController::ReloadFromSettings() { } void EmulatedController::ReloadColorsFromSettings() { - const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); const auto& player = Settings::values.players.GetValue()[player_index]; // Avoid updating colors if overridden by physical controller @@ -215,7 +216,7 @@ void EmulatedController::LoadDevices() { } void EmulatedController::LoadTASParams() { - const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); Common::ParamPackage common_params{}; common_params.Set("engine", "tas"); common_params.Set("port", static_cast<int>(player_index)); @@ -264,7 +265,7 @@ void EmulatedController::LoadTASParams() { } void EmulatedController::LoadVirtualGamepadParams() { - const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); Common::ParamPackage common_params{}; common_params.Set("engine", "virtual_gamepad"); common_params.Set("port", static_cast<int>(player_index)); @@ -615,7 +616,7 @@ bool EmulatedController::IsConfiguring() const { } void EmulatedController::SaveCurrentConfig() { - const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); auto& player = Settings::values.players.GetValue()[player_index]; player.connected = is_connected; player.controller_type = MapNPadToSettingsType(npad_type); @@ -1212,7 +1213,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v if (!output_devices[device_index]) { return false; } - const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); const auto& player = Settings::values.players.GetValue()[player_index]; const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f; @@ -1238,7 +1239,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v } bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { - const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); const auto& player = Settings::values.players.GetValue()[player_index]; if (!player.vibration_enabled) { @@ -1648,7 +1649,7 @@ void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { } if (is_connected) { LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", - NpadIdTypeToIndex(npad_id_type)); + Service::HID::NpadIdTypeToIndex(npad_id_type)); } npad_type = npad_type_; } diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index cf53c04d9..2cf25a870 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -6,6 +6,7 @@ #include "core/hid/emulated_controller.h" #include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" +#include "core/hle/service/hid/hid_util.h" namespace Core::HID { @@ -98,11 +99,11 @@ const EmulatedDevices* HIDCore::GetEmulatedDevices() const { } EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) { - return GetEmulatedController(IndexToNpadIdType(index)); + return GetEmulatedController(Service::HID::IndexToNpadIdType(index)); } const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) const { - return GetEmulatedController(IndexToNpadIdType(index)); + return GetEmulatedController(Service::HID::IndexToNpadIdType(index)); } void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) { diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 70fcc6b69..4bf285f36 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -8,6 +8,7 @@ #include "common/common_types.h" #include "common/point.h" #include "common/uuid.h" +#include "common/vector_math.h" namespace Core::HID { @@ -598,6 +599,29 @@ struct SixAxisSensorIcInformation { static_assert(sizeof(SixAxisSensorIcInformation) == 0xC8, "SixAxisSensorIcInformation is an invalid size"); +// This is nn::hid::SixAxisSensorAttribute +struct SixAxisSensorAttribute { + union { + u32 raw{}; + BitField<0, 1, u32> is_connected; + BitField<1, 1, u32> is_interpolated; + }; +}; +static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size"); + +// This is nn::hid::SixAxisSensorState +struct SixAxisSensorState { + s64 delta_time{}; + s64 sampling_number{}; + Common::Vec3f accel{}; + Common::Vec3f gyro{}; + Common::Vec3f rotation{}; + std::array<Common::Vec3f, 3> orientation{}; + SixAxisSensorAttribute attribute{}; + INSERT_PADDING_BYTES(4); // Reserved +}; +static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size"); + // This is nn::hid::VibrationDeviceHandle struct VibrationDeviceHandle { NpadStyleIndex npad_type{NpadStyleIndex::None}; @@ -708,60 +732,4 @@ struct UniquePadId { }; static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size"); -/// Converts a NpadIdType to an array index. -constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) { - switch (npad_id_type) { - case NpadIdType::Player1: - return 0; - case NpadIdType::Player2: - return 1; - case NpadIdType::Player3: - return 2; - case NpadIdType::Player4: - return 3; - case NpadIdType::Player5: - return 4; - case NpadIdType::Player6: - return 5; - case NpadIdType::Player7: - return 6; - case NpadIdType::Player8: - return 7; - case NpadIdType::Handheld: - return 8; - case NpadIdType::Other: - return 9; - default: - return 0; - } -} - -/// Converts an array index to a NpadIdType -constexpr NpadIdType IndexToNpadIdType(size_t index) { - switch (index) { - case 0: - return NpadIdType::Player1; - case 1: - return NpadIdType::Player2; - case 2: - return NpadIdType::Player3; - case 3: - return NpadIdType::Player4; - case 4: - return NpadIdType::Player5; - case 5: - return NpadIdType::Player6; - case 6: - return NpadIdType::Player7; - case 7: - return NpadIdType::Player8; - case 8: - return NpadIdType::Handheld; - case 9: - return NpadIdType::Other; - default: - return NpadIdType::Invalid; - } -} - } // namespace Core::HID diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp index 11359f318..a6bdd28f2 100644 --- a/src/core/hid/input_interpreter.cpp +++ b/src/core/hid/input_interpreter.cpp @@ -13,14 +13,14 @@ InputInterpreter::InputInterpreter(Core::System& system) : npad{system.ServiceManager() .GetService<Service::HID::IHidServer>("hid") ->GetResourceManager() - ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} { + ->GetNpad()} { ResetButtonStates(); } InputInterpreter::~InputInterpreter() = default; void InputInterpreter::PollInput() { - const auto button_state = npad.GetAndResetPressState(); + const auto button_state = npad->GetAndResetPressState(); previous_index = current_index; current_index = (current_index + 1) % button_states.size(); diff --git a/src/core/hid/input_interpreter.h b/src/core/hid/input_interpreter.h index 8c521b381..3569aac93 100644 --- a/src/core/hid/input_interpreter.h +++ b/src/core/hid/input_interpreter.h @@ -16,7 +16,7 @@ enum class NpadButton : u64; } namespace Service::HID { -class Controller_NPad; +class NPad; } /** @@ -101,7 +101,7 @@ public: } private: - Service::HID::Controller_NPad& npad; + std::shared_ptr<Service::HID::NPad> npad; /// Stores 9 consecutive button states polled from HID. std::array<Core::HID::NpadButton, 9> button_states{}; diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 9d05f9801..0507b14e7 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -32,7 +32,7 @@ public: {10200, nullptr, "SendFriendRequestForApplication"}, {10211, nullptr, "AddFacedFriendRequestForApplication"}, {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"}, - {10420, nullptr, "IsBlockedUserListCacheAvailable"}, + {10420, &IFriendService::CheckBlockedUserListAvailability, "CheckBlockedUserListAvailability"}, {10421, nullptr, "EnsureBlockedUserListAvailable"}, {10500, nullptr, "GetProfileList"}, {10600, nullptr, "DeclareOpenOnlinePlaySession"}, @@ -206,6 +206,17 @@ private: rb.Push(true); } + void CheckBlockedUserListAvailability(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto uuid{rp.PopRaw<Common::UUID>()}; + + LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString()); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(true); + } + KernelHelpers::ServiceContext service_context; Kernel::KEvent* completion_event; diff --git a/src/core/hle/service/hid/controllers/console_six_axis.cpp b/src/core/hle/service/hid/controllers/console_six_axis.cpp new file mode 100644 index 000000000..b2bf1d78d --- /dev/null +++ b/src/core/hle/service/hid/controllers/console_six_axis.cpp @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/core_timing.h" +#include "core/hid/emulated_console.h" +#include "core/hid/hid_core.h" +#include "core/hle/service/hid/controllers/console_six_axis.h" +#include "core/memory.h" + +namespace Service::HID { +constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; + +ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) + : ControllerBase{hid_core_} { + console = hid_core.GetEmulatedConsole(); + static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size, + "ConsoleSharedMemory is bigger than the shared memory"); + shared_memory = std::construct_at( + reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); +} + +ConsoleSixAxis::~ConsoleSixAxis() = default; + +void ConsoleSixAxis::OnInit() {} + +void ConsoleSixAxis::OnRelease() {} + +void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { + if (!IsControllerActivated()) { + return; + } + + const auto motion_status = console->GetMotion(); + + shared_memory->sampling_number++; + shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; + shared_memory->verticalization_error = motion_status.verticalization_error; + shared_memory->gyro_bias = motion_status.gyro_bias; +} + +} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/console_six_axis.h b/src/core/hle/service/hid/controllers/console_six_axis.h new file mode 100644 index 000000000..5b7c6a29a --- /dev/null +++ b/src/core/hle/service/hid/controllers/console_six_axis.h @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/vector_math.h" +#include "core/hle/service/hid/controllers/controller_base.h" + +namespace Core::HID { +class EmulatedConsole; +} // namespace Core::HID + +namespace Service::HID { +class ConsoleSixAxis final : public ControllerBase { +public: + explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + ~ConsoleSixAxis() override; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; + +private: + // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat + struct ConsoleSharedMemory { + u64 sampling_number{}; + bool is_seven_six_axis_sensor_at_rest{}; + INSERT_PADDING_BYTES(3); // padding + f32 verticalization_error{}; + Common::Vec3f gyro_bias{}; + INSERT_PADDING_BYTES(4); // padding + }; + static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); + + ConsoleSharedMemory* shared_memory = nullptr; + Core::HID::EmulatedConsole* console = nullptr; +}; +} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 8ec9f4a95..9de19ebfc 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -13,7 +13,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; -Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) +DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} { static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size, "DebugPadSharedMemory is bigger than the shared memory"); @@ -22,13 +22,13 @@ Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_ controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); } -Controller_DebugPad::~Controller_DebugPad() = default; +DebugPad::~DebugPad() = default; -void Controller_DebugPad::OnInit() {} +void DebugPad::OnInit() {} -void Controller_DebugPad::OnRelease() {} +void DebugPad::OnRelease() {} -void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { shared_memory->debug_pad_lifo.buffer_count = 0; shared_memory->debug_pad_lifo.buffer_tail = 0; diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 68ff0ea79..5566dba77 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -15,10 +15,10 @@ struct AnalogStickState; } // namespace Core::HID namespace Service::HID { -class Controller_DebugPad final : public ControllerBase { +class DebugPad final : public ControllerBase { public: - explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); - ~Controller_DebugPad() override; + explicit DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + ~DebugPad() override; // Called when the controller is initialized void OnInit() override; diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 63eecd42b..59b2ec73c 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -23,7 +23,7 @@ constexpr f32 Square(s32 num) { return static_cast<f32>(num * num); } -Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) +Gesture::Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase(hid_core_) { static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size, "GestureSharedMemory is bigger than the shared memory"); @@ -31,17 +31,17 @@ Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_sh reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); console = hid_core.GetEmulatedConsole(); } -Controller_Gesture::~Controller_Gesture() = default; +Gesture::~Gesture() = default; -void Controller_Gesture::OnInit() { +void Gesture::OnInit() { shared_memory->gesture_lifo.buffer_count = 0; shared_memory->gesture_lifo.buffer_tail = 0; force_update = true; } -void Controller_Gesture::OnRelease() {} +void Gesture::OnRelease() {} -void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { shared_memory->gesture_lifo.buffer_count = 0; shared_memory->gesture_lifo.buffer_tail = 0; @@ -64,7 +64,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { UpdateGestureSharedMemory(gesture, time_difference); } -void Controller_Gesture::ReadTouchInput() { +void Gesture::ReadTouchInput() { if (!Settings::values.touchscreen.enabled) { fingers = {}; return; @@ -76,8 +76,7 @@ void Controller_Gesture::ReadTouchInput() { } } -bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, - f32 time_difference) { +bool Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); if (force_update) { force_update = false; @@ -100,8 +99,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, return false; } -void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, - f32 time_difference) { +void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference) { GestureType type = GestureType::Idle; GestureAttribute attributes{}; @@ -138,8 +136,8 @@ void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, shared_memory->gesture_lifo.WriteNextEntry(next_state); } -void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, - GestureAttribute& attributes) { +void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, + GestureAttribute& attributes) { const auto& last_entry = GetLastGestureEntry(); gesture.detection_count++; @@ -152,8 +150,8 @@ void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& typ } } -void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, - f32 time_difference) { +void Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, + f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); // Promote to pan type if touch moved @@ -186,9 +184,8 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Gestu } } -void Controller_Gesture::EndGesture(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type, - GestureAttribute& attributes, f32 time_difference) { +void Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, + GestureType& type, GestureAttribute& attributes, f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); if (last_gesture_props.active_points != 0) { @@ -222,9 +219,8 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture, } } -void Controller_Gesture::SetTapEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type, - GestureAttribute& attributes) { +void Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, + GestureType& type, GestureAttribute& attributes) { type = GestureType::Tap; gesture = last_gesture_props; force_update = true; @@ -236,9 +232,8 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, } } -void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type, - f32 time_difference) { +void Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, + GestureType& type, f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); next_state.delta = gesture.mid_point - last_entry.pos; @@ -263,9 +258,8 @@ void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, } } -void Controller_Gesture::EndPanEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type, - f32 time_difference) { +void Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, + GestureType& type, f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); next_state.vel_x = static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); @@ -287,8 +281,8 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, force_update = true; } -void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type) { +void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, + GestureType& type) { const auto& last_entry = GetLastGestureEntry(); type = GestureType::Swipe; @@ -311,11 +305,11 @@ void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, next_state.direction = GestureDirection::Up; } -const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { +const Gesture::GestureState& Gesture::GetLastGestureEntry() const { return shared_memory->gesture_lifo.ReadCurrentEntry().state; } -Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { +Gesture::GestureProperties Gesture::GetGestureProperties() { GestureProperties gesture; std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 0d6099ea0..4c6f8ee07 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -12,10 +12,10 @@ #include "core/hle/service/hid/ring_lifo.h" namespace Service::HID { -class Controller_Gesture final : public ControllerBase { +class Gesture final : public ControllerBase { public: - explicit Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); - ~Controller_Gesture() override; + explicit Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + ~Gesture() override; // Called when the controller is initialized void OnInit() override; diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 117d87433..ddb1b0ba4 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -12,7 +12,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; -Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) +Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} { static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size, "KeyboardSharedMemory is bigger than the shared memory"); @@ -21,13 +21,13 @@ Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_ emulated_devices = hid_core.GetEmulatedDevices(); } -Controller_Keyboard::~Controller_Keyboard() = default; +Keyboard::~Keyboard() = default; -void Controller_Keyboard::OnInit() {} +void Keyboard::OnInit() {} -void Controller_Keyboard::OnRelease() {} +void Keyboard::OnRelease() {} -void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { shared_memory->keyboard_lifo.buffer_count = 0; shared_memory->keyboard_lifo.buffer_tail = 0; diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index 7532f53c6..172ec1309 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -14,10 +14,10 @@ struct KeyboardKey; } // namespace Core::HID namespace Service::HID { -class Controller_Keyboard final : public ControllerBase { +class Keyboard final : public ControllerBase { public: - explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); - ~Controller_Keyboard() override; + explicit Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + ~Keyboard() override; // Called when the controller is initialized void OnInit() override; diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 0afc66681..6e5a04e34 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -12,8 +12,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; -Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) - : ControllerBase{hid_core_} { +Mouse::Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} { static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size, "MouseSharedMemory is bigger than the shared memory"); shared_memory = std::construct_at( @@ -21,12 +20,12 @@ Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared emulated_devices = hid_core.GetEmulatedDevices(); } -Controller_Mouse::~Controller_Mouse() = default; +Mouse::~Mouse() = default; -void Controller_Mouse::OnInit() {} -void Controller_Mouse::OnRelease() {} +void Mouse::OnInit() {} +void Mouse::OnRelease() {} -void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { shared_memory->mouse_lifo.buffer_count = 0; shared_memory->mouse_lifo.buffer_tail = 0; diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 733d00577..a80f3823f 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -14,10 +14,10 @@ struct AnalogStickState; } // namespace Core::HID namespace Service::HID { -class Controller_Mouse final : public ControllerBase { +class Mouse final : public ControllerBase { public: - explicit Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); - ~Controller_Mouse() override; + explicit Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + ~Mouse() override; // Called when the controller is initialized void OnInit() override; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 127af2b82..08ee9de9c 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -18,6 +18,7 @@ #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/errors.h" +#include "core/hle/service/hid/hid_util.h" #include "core/hle/service/kernel_helpers.h" namespace Service::HID { @@ -29,60 +30,8 @@ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ Core::HID::NpadIdType::Handheld, }; -bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) { - switch (npad_id) { - case Core::HID::NpadIdType::Player1: - case Core::HID::NpadIdType::Player2: - case Core::HID::NpadIdType::Player3: - case Core::HID::NpadIdType::Player4: - case Core::HID::NpadIdType::Player5: - case Core::HID::NpadIdType::Player6: - case Core::HID::NpadIdType::Player7: - case Core::HID::NpadIdType::Player8: - case Core::HID::NpadIdType::Other: - case Core::HID::NpadIdType::Handheld: - return true; - default: - LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id); - return false; - } -} - -Result Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) { - const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)); - const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType; - const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; - - if (!npad_type) { - return VibrationInvalidStyleIndex; - } - if (!npad_id) { - return VibrationInvalidNpadId; - } - if (!device_index) { - return VibrationDeviceIndexOutOfRange; - } - - return ResultSuccess; -} - -Result Controller_NPad::VerifyValidSixAxisSensorHandle( - const Core::HID::SixAxisSensorHandle& device_handle) { - const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id)); - const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; - - if (!npad_id) { - return InvalidNpadId; - } - if (!device_index) { - return NpadDeviceIndexOutOfRange; - } - - return ResultSuccess; -} - -Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, - KernelHelpers::ServiceContext& service_context_) +NPad::NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, + KernelHelpers::ServiceContext& service_context_) : ControllerBase{hid_core_}, service_context{service_context_} { static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size); for (std::size_t i = 0; i < controller_data.size(); ++i) { @@ -103,7 +52,7 @@ Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_m } } -Controller_NPad::~Controller_NPad() { +NPad::~NPad() { for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; controller.device->DeleteCallback(controller.callback_key); @@ -111,8 +60,7 @@ Controller_NPad::~Controller_NPad() { OnRelease(); } -void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, - std::size_t controller_idx) { +void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx) { if (type == Core::HID::ControllerTriggerType::All) { ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx); ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); @@ -150,7 +98,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, } } -void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { +void NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { auto& controller = GetControllerFromNpadIdType(npad_id); if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) { return; @@ -350,7 +298,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { hid_core.SetLastActiveController(npad_id); } -void Controller_NPad::OnInit() { +void NPad::OnInit() { if (!IsControllerActivated()) { return; } @@ -384,7 +332,7 @@ void Controller_NPad::OnInit() { } } -void Controller_NPad::WriteEmptyEntry(NpadInternalState* npad) { +void NPad::WriteEmptyEntry(NpadInternalState* npad) { NPadGenericState dummy_pad_state{}; NpadGcTriggerState dummy_gc_state{}; dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1; @@ -405,7 +353,7 @@ void Controller_NPad::WriteEmptyEntry(NpadInternalState* npad) { npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state); } -void Controller_NPad::OnRelease() { +void NPad::OnRelease() { is_controller_initialized = false; for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; @@ -416,7 +364,7 @@ void Controller_NPad::OnRelease() { } } -void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { +void NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { std::scoped_lock lock{mutex}; auto& controller = GetControllerFromNpadIdType(npad_id); const auto controller_type = controller.device->GetNpadStyleIndex(); @@ -485,7 +433,7 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { } } -void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { return; } @@ -615,134 +563,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { } } -void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!IsControllerActivated()) { - return; - } - - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - - const auto& controller_type = controller.device->GetNpadStyleIndex(); - - if (controller_type == Core::HID::NpadStyleIndex::None || - !controller.device->IsConnected()) { - continue; - } - - auto* npad = controller.shared_memory; - const auto& motion_state = controller.device->GetMotions(); - auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; - auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; - auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state; - auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state; - auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; - auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; - - // Clear previous state - sixaxis_fullkey_state = {}; - sixaxis_handheld_state = {}; - sixaxis_dual_left_state = {}; - sixaxis_dual_right_state = {}; - sixaxis_left_lifo_state = {}; - sixaxis_right_lifo_state = {}; - - if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { - controller.sixaxis_at_rest = true; - for (std::size_t e = 0; e < motion_state.size(); ++e) { - controller.sixaxis_at_rest = - controller.sixaxis_at_rest && motion_state[e].is_at_rest; - } - } - - const auto set_motion_state = [&](SixAxisSensorState& state, - const Core::HID::ControllerMotion& hid_state) { - using namespace std::literals::chrono_literals; - static constexpr SixAxisSensorState default_motion_state = { - .delta_time = std::chrono::nanoseconds(5ms).count(), - .accel = {0, 0, -1.0f}, - .orientation = - { - Common::Vec3f{1.0f, 0, 0}, - Common::Vec3f{0, 1.0f, 0}, - Common::Vec3f{0, 0, 1.0f}, - }, - .attribute = {1}, - }; - if (!controller.sixaxis_sensor_enabled) { - state = default_motion_state; - return; - } - if (!Settings::values.motion_enabled.GetValue()) { - state = default_motion_state; - return; - } - state.attribute.is_connected.Assign(1); - state.delta_time = std::chrono::nanoseconds(5ms).count(); - state.accel = hid_state.accel; - state.gyro = hid_state.gyro; - state.rotation = hid_state.rotation; - state.orientation = hid_state.orientation; - }; - - switch (controller_type) { - case Core::HID::NpadStyleIndex::None: - ASSERT(false); - break; - case Core::HID::NpadStyleIndex::ProController: - set_motion_state(sixaxis_fullkey_state, motion_state[0]); - break; - case Core::HID::NpadStyleIndex::Handheld: - set_motion_state(sixaxis_handheld_state, motion_state[0]); - break; - case Core::HID::NpadStyleIndex::JoyconDual: - set_motion_state(sixaxis_dual_left_state, motion_state[0]); - set_motion_state(sixaxis_dual_right_state, motion_state[1]); - break; - case Core::HID::NpadStyleIndex::JoyconLeft: - set_motion_state(sixaxis_left_lifo_state, motion_state[0]); - break; - case Core::HID::NpadStyleIndex::JoyconRight: - set_motion_state(sixaxis_right_lifo_state, motion_state[1]); - break; - case Core::HID::NpadStyleIndex::Pokeball: - using namespace std::literals::chrono_literals; - set_motion_state(sixaxis_fullkey_state, motion_state[0]); - sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count(); - break; - default: - break; - } - - sixaxis_fullkey_state.sampling_number = - npad->sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_handheld_state.sampling_number = - npad->sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_dual_left_state.sampling_number = - npad->sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_dual_right_state.sampling_number = - npad->sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_left_lifo_state.sampling_number = - npad->sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_right_lifo_state.sampling_number = - npad->sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; - - if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { - // This buffer only is updated on handheld on HW - npad->sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); - } else { - // Handheld doesn't update this buffer on HW - npad->sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); - } - - npad->sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); - npad->sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); - npad->sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); - npad->sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); - } -} - -void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { +void NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { hid_core.SetSupportedStyleTag(style_set); if (is_controller_initialized) { @@ -753,14 +574,14 @@ void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { is_controller_initialized = true; } -Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { +Core::HID::NpadStyleTag NPad::GetSupportedStyleSet() const { if (!is_controller_initialized) { return {Core::HID::NpadStyleSet::None}; } return hid_core.GetSupportedStyleTag(); } -Result Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) { +Result NPad::SetSupportedNpadIdTypes(std::span<const u8> data) { constexpr std::size_t max_number_npad_ids = 0xa; const auto length = data.size(); ASSERT(length > 0 && (length % sizeof(u32)) == 0); @@ -776,17 +597,17 @@ Result Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) { return ResultSuccess; } -void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { +void NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { const auto copy_amount = supported_npad_id_types.size() * sizeof(u32); ASSERT(max_length <= copy_amount); std::memcpy(data, supported_npad_id_types.data(), copy_amount); } -std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const { +std::size_t NPad::GetSupportedNpadIdTypesSize() const { return supported_npad_id_types.size(); } -void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { +void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { if (joy_hold_type != NpadJoyHoldType::Horizontal && joy_hold_type != NpadJoyHoldType::Vertical) { LOG_ERROR(Service_HID, "Npad joy hold type needs to be valid, joy_hold_type={}", @@ -796,11 +617,11 @@ void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { hold_type = joy_hold_type; } -Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const { +NPad::NpadJoyHoldType NPad::GetHoldType() const { return hold_type; } -void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { +void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) { ASSERT_MSG(false, "Activation mode should be always None, Single or Dual"); return; @@ -809,21 +630,20 @@ void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode a handheld_activation_mode = activation_mode; } -Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const { +NPad::NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const { return handheld_activation_mode; } -void Controller_NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) { +void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) { communication_mode = communication_mode_; } -Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode() const { +NPad::NpadCommunicationMode NPad::GetNpadCommunicationMode() const { return communication_mode; } -bool Controller_NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, - NpadJoyDeviceType npad_device_type, - NpadJoyAssignmentMode assignment_mode) { +bool NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, + NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode) { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); return false; @@ -892,9 +712,8 @@ bool Controller_NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID: return true; } -bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, - std::size_t device_index, - const Core::HID::VibrationValue& vibration_value) { +bool NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, + const Core::HID::VibrationValue& vibration_value) { auto& controller = GetControllerFromNpadIdType(npad_id); if (!controller.device->IsConnected()) { return false; @@ -938,10 +757,9 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, return controller.device->SetVibration(device_index, vibration); } -void Controller_NPad::VibrateController( - const Core::HID::VibrationDeviceHandle& vibration_device_handle, - const Core::HID::VibrationValue& vibration_value) { - if (IsDeviceHandleValid(vibration_device_handle).IsError()) { +void NPad::VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, + const Core::HID::VibrationValue& vibration_value) { + if (IsVibrationHandleValid(vibration_device_handle).IsError()) { return; } @@ -985,7 +803,7 @@ void Controller_NPad::VibrateController( } } -void Controller_NPad::VibrateControllers( +void NPad::VibrateControllers( std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, std::span<const Core::HID::VibrationValue> vibration_values) { if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { @@ -1002,9 +820,9 @@ void Controller_NPad::VibrateControllers( } } -Core::HID::VibrationValue Controller_NPad::GetLastVibration( +Core::HID::VibrationValue NPad::GetLastVibration( const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { - if (IsDeviceHandleValid(vibration_device_handle).IsError()) { + if (IsVibrationHandleValid(vibration_device_handle).IsError()) { return {}; } @@ -1013,9 +831,9 @@ Core::HID::VibrationValue Controller_NPad::GetLastVibration( return controller.vibration[device_index].latest_vibration_value; } -void Controller_NPad::InitializeVibrationDevice( +void NPad::InitializeVibrationDevice( const Core::HID::VibrationDeviceHandle& vibration_device_handle) { - if (IsDeviceHandleValid(vibration_device_handle).IsError()) { + if (IsVibrationHandleValid(vibration_device_handle).IsError()) { return; } @@ -1024,8 +842,8 @@ void Controller_NPad::InitializeVibrationDevice( InitializeVibrationDeviceAtIndex(npad_index, device_index); } -void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, - std::size_t device_index) { +void NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, + std::size_t device_index) { auto& controller = GetControllerFromNpadIdType(npad_id); if (!Settings::values.vibration_enabled.GetValue()) { controller.vibration[device_index].device_mounted = false; @@ -1036,13 +854,13 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npa controller.device->IsVibrationEnabled(device_index); } -void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { +void NPad::SetPermitVibrationSession(bool permit_vibration_session) { permit_vibration_session_enabled = permit_vibration_session; } -bool Controller_NPad::IsVibrationDeviceMounted( +bool NPad::IsVibrationDeviceMounted( const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { - if (IsDeviceHandleValid(vibration_device_handle).IsError()) { + if (IsVibrationHandleValid(vibration_device_handle).IsError()) { return false; } @@ -1051,7 +869,7 @@ bool Controller_NPad::IsVibrationDeviceMounted( return controller.vibration[device_index].device_mounted; } -Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { +Kernel::KReadableEvent& NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); // Fallback to player 1 @@ -1063,18 +881,17 @@ Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::Npad return controller.styleset_changed_event->GetReadableEvent(); } -void Controller_NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { +void NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { const auto& controller = GetControllerFromNpadIdType(npad_id); controller.styleset_changed_event->Signal(); } -void Controller_NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, - Core::HID::NpadIdType npad_id) { +void NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id) { UpdateControllerAt(controller, npad_id, true); } -void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, - Core::HID::NpadIdType npad_id, bool connected) { +void NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, Core::HID::NpadIdType npad_id, + bool connected) { auto& controller = GetControllerFromNpadIdType(npad_id); if (!connected) { DisconnectNpad(npad_id); @@ -1085,7 +902,7 @@ void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, InitNewlyAddedController(npad_id); } -Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { +Result NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); return InvalidNpadId; @@ -1134,54 +951,9 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { return ResultSuccess; } -Result Controller_NPad::SetGyroscopeZeroDriftMode( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::GyroscopeZeroDriftMode drift_mode) { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - auto& sixaxis = GetSixaxisState(sixaxis_handle); - auto& controller = GetControllerFromHandle(sixaxis_handle); - sixaxis.gyroscope_zero_drift_mode = drift_mode; - controller.device->SetGyroscopeZeroDriftMode(drift_mode); - - return ResultSuccess; -} - -Result Controller_NPad::GetGyroscopeZeroDriftMode( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::GyroscopeZeroDriftMode& drift_mode) const { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - drift_mode = sixaxis.gyroscope_zero_drift_mode; - - return ResultSuccess; -} - -Result Controller_NPad::IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool& is_at_rest) const { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& controller = GetControllerFromHandle(sixaxis_handle); - is_at_rest = controller.sixaxis_at_rest; - return ResultSuccess; -} - -Result Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor( +Result NPad::IsFirmwareUpdateAvailableForSixAxisSensor( const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); if (is_valid.IsError()) { LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); return is_valid; @@ -1192,65 +964,9 @@ Result Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor( return ResultSuccess; } -Result Controller_NPad::EnableSixAxisSensorUnalteredPassthrough( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - auto& sixaxis = GetSixaxisState(sixaxis_handle); - sixaxis.unaltered_passtrough = is_enabled; - return ResultSuccess; -} - -Result Controller_NPad::IsSixAxisSensorUnalteredPassthroughEnabled( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - is_enabled = sixaxis.unaltered_passtrough; - return ResultSuccess; -} - -Result Controller_NPad::LoadSixAxisSensorCalibrationParameter( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorCalibrationParameter& calibration) const { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - // TODO: Request this data to the controller. On error return 0xd8ca - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - calibration = sixaxis.calibration; - return ResultSuccess; -} - -Result Controller_NPad::GetSixAxisSensorIcInformation( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorIcInformation& ic_information) const { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - // TODO: Request this data to the controller. On error return 0xd8ca - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - ic_information = sixaxis.ic_information; - return ResultSuccess; -} - -Result Controller_NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( +Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( const Core::HID::SixAxisSensorHandle& sixaxis_handle) { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); if (is_valid.IsError()) { LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); return is_valid; @@ -1262,83 +978,32 @@ Result Controller_NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( return ResultSuccess; } -Result Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool sixaxis_status) { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - auto& controller = GetControllerFromHandle(sixaxis_handle); - controller.sixaxis_sensor_enabled = sixaxis_status; - return ResultSuccess; +NPad::SixAxisLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) { + return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo; } -Result Controller_NPad::IsSixAxisSensorFusionEnabled( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_fusion_enabled) const { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - is_fusion_enabled = sixaxis.is_fusion_enabled; - - return ResultSuccess; +NPad::SixAxisLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) { + return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo; } -Result Controller_NPad::SetSixAxisFusionEnabled( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_fusion_enabled) { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - auto& sixaxis = GetSixaxisState(sixaxis_handle); - sixaxis.is_fusion_enabled = is_fusion_enabled; - - return ResultSuccess; +NPad::SixAxisLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) { + return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo; } -Result Controller_NPad::SetSixAxisFusionParameters( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto param1 = sixaxis_fusion_parameters.parameter1; - if (param1 < 0.0f || param1 > 1.0f) { - return InvalidSixAxisFusionRange; - } - - auto& sixaxis = GetSixaxisState(sixaxis_handle); - sixaxis.fusion = sixaxis_fusion_parameters; - - return ResultSuccess; +NPad::SixAxisLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) { + return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo; } -Result Controller_NPad::GetSixAxisFusionParameters( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters& parameters) const { - const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); - if (is_valid.IsError()) { - LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); - return is_valid; - } - - const auto& sixaxis = GetSixaxisState(sixaxis_handle); - parameters = sixaxis.fusion; +NPad::SixAxisLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) { + return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo; +} - return ResultSuccess; +NPad::SixAxisLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) { + return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo; } -Result Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, - Core::HID::NpadIdType npad_id_2) { +Result NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, + Core::HID::NpadIdType npad_id_2) { if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, npad_id_2); @@ -1400,18 +1065,17 @@ Result Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, return ResultSuccess; } -void Controller_NPad::StartLRAssignmentMode() { +void NPad::StartLRAssignmentMode() { // Nothing internally is used for lr assignment mode. Since we have the ability to set the // controller types from boot, it doesn't really matter about showing a selection screen is_in_lr_assignment_mode = true; } -void Controller_NPad::StopLRAssignmentMode() { +void NPad::StopLRAssignmentMode() { is_in_lr_assignment_mode = false; } -Result Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, - Core::HID::NpadIdType npad_id_2) { +Result NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2) { if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, npad_id_2); @@ -1442,8 +1106,7 @@ Result Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, return ResultSuccess; } -Result Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id, - Core::HID::LedPattern& pattern) const { +Result NPad::GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); return InvalidNpadId; @@ -1453,8 +1116,8 @@ Result Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id, return ResultSuccess; } -Result Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, - bool& is_valid) const { +Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, + bool& is_valid) const { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); return InvalidNpadId; @@ -1464,8 +1127,8 @@ Result Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(Core::HID:: return ResultSuccess; } -Result Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled( - bool is_protection_enabled, Core::HID::NpadIdType npad_id) { +Result NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, + Core::HID::NpadIdType npad_id) { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); return InvalidNpadId; @@ -1475,11 +1138,11 @@ Result Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled( return ResultSuccess; } -void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { +void NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { analog_stick_use_center_clamp = use_center_clamp; } -void Controller_NPad::ClearAllConnectedControllers() { +void NPad::ClearAllConnectedControllers() { for (auto& controller : controller_data) { if (controller.device->IsConnected() && controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { @@ -1489,13 +1152,13 @@ void Controller_NPad::ClearAllConnectedControllers() { } } -void Controller_NPad::DisconnectAllConnectedControllers() { +void NPad::DisconnectAllConnectedControllers() { for (auto& controller : controller_data) { controller.device->Disconnect(); } } -void Controller_NPad::ConnectAllDisconnectedControllers() { +void NPad::ConnectAllDisconnectedControllers() { for (auto& controller : controller_data) { if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None && !controller.device->IsConnected()) { @@ -1504,18 +1167,18 @@ void Controller_NPad::ConnectAllDisconnectedControllers() { } } -void Controller_NPad::ClearAllControllers() { +void NPad::ClearAllControllers() { for (auto& controller : controller_data) { controller.device->Disconnect(); controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); } } -Core::HID::NpadButton Controller_NPad::GetAndResetPressState() { +Core::HID::NpadButton NPad::GetAndResetPressState() { return static_cast<Core::HID::NpadButton>(press_state.exchange(0)); } -void Controller_NPad::ApplyNpadSystemCommonPolicy() { +void NPad::ApplyNpadSystemCommonPolicy() { Core::HID::NpadStyleTag styletag{}; styletag.fullkey.Assign(1); styletag.handheld.Assign(1); @@ -1540,7 +1203,7 @@ void Controller_NPad::ApplyNpadSystemCommonPolicy() { supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld; } -bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { +bool NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { if (controller == Core::HID::NpadStyleIndex::Handheld) { const bool support_handheld = std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), @@ -1591,51 +1254,50 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller return false; } -Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) { +NPad::NpadControllerData& NPad::GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle) { const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); return GetControllerFromNpadIdType(npad_id); } -const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) const { +const NPad::NpadControllerData& NPad::GetControllerFromHandle( + const Core::HID::VibrationDeviceHandle& device_handle) const { const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); return GetControllerFromNpadIdType(npad_id); } -Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle) { +NPad::NpadControllerData& NPad::GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) { const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); return GetControllerFromNpadIdType(npad_id); } -const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle) const { +const NPad::NpadControllerData& NPad::GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) const { const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); return GetControllerFromNpadIdType(npad_id); } -Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( - Core::HID::NpadIdType npad_id) { +NPad::NpadControllerData& NPad::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); npad_id = Core::HID::NpadIdType::Player1; } - const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); + const auto npad_index = NpadIdTypeToIndex(npad_id); return controller_data[npad_index]; } -const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( +const NPad::NpadControllerData& NPad::GetControllerFromNpadIdType( Core::HID::NpadIdType npad_id) const { if (!IsNpadIdValid(npad_id)) { LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); npad_id = Core::HID::NpadIdType::Player1; } - const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); + const auto npad_index = NpadIdTypeToIndex(npad_id); return controller_data[npad_index]; } -Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties( +Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( const Core::HID::SixAxisSensorHandle& sixaxis_handle) { auto& controller = GetControllerFromHandle(sixaxis_handle); switch (sixaxis_handle.npad_type) { @@ -1658,7 +1320,7 @@ Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties( } } -const Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties( +const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { const auto& controller = GetControllerFromHandle(sixaxis_handle); switch (sixaxis_handle.npad_type) { @@ -1681,65 +1343,13 @@ const Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties( } } -Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState( - const Core::HID::SixAxisSensorHandle& sixaxis_handle) { - auto& controller = GetControllerFromHandle(sixaxis_handle); - switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Pokeball: - return controller.sixaxis_fullkey; - case Core::HID::NpadStyleIndex::Handheld: - return controller.sixaxis_handheld; - case Core::HID::NpadStyleIndex::JoyconDual: - if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { - return controller.sixaxis_dual_left; - } - return controller.sixaxis_dual_right; - case Core::HID::NpadStyleIndex::JoyconLeft: - return controller.sixaxis_left; - case Core::HID::NpadStyleIndex::JoyconRight: - return controller.sixaxis_right; - default: - return controller.sixaxis_unknown; - } -} - -const Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState( - const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { - const auto& controller = GetControllerFromHandle(sixaxis_handle); - switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Pokeball: - return controller.sixaxis_fullkey; - case Core::HID::NpadStyleIndex::Handheld: - return controller.sixaxis_handheld; - case Core::HID::NpadStyleIndex::JoyconDual: - if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { - return controller.sixaxis_dual_left; - } - return controller.sixaxis_dual_right; - case Core::HID::NpadStyleIndex::JoyconLeft: - return controller.sixaxis_left; - case Core::HID::NpadStyleIndex::JoyconRight: - return controller.sixaxis_right; - default: - return controller.sixaxis_unknown; - } -} - -Controller_NPad::AppletDetailedUiType Controller_NPad::GetAppletDetailedUiType( - Core::HID::NpadIdType npad_id) { - - auto controller = GetControllerFromNpadIdType(npad_id); - auto shared_memory = controller.shared_memory; - Service::HID::Controller_NPad::AppletFooterUiType applet_footer_type = - shared_memory->applet_footer_type; +NPad::AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) { + const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory; - Controller_NPad::AppletDetailedUiType detailed_ui_type{ + return { .ui_variant = 0, - .footer = applet_footer_type, + .footer = shared_memory->applet_footer_type, }; - return detailed_ui_type; } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index cd93abdd1..9167c93f0 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -10,7 +10,6 @@ #include "common/bit_field.h" #include "common/common_types.h" -#include "common/vector_math.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" @@ -34,11 +33,11 @@ union Result; namespace Service::HID { -class Controller_NPad final : public ControllerBase { +class NPad final : public ControllerBase { public: - explicit Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, - KernelHelpers::ServiceContext& service_context_); - ~Controller_NPad() override; + explicit NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, + KernelHelpers::ServiceContext& service_context_); + ~NPad() override; // Called when the controller is initialized void OnInit() override; @@ -49,9 +48,6 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - // When the controller is requesting a motion update for the shared memory - void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override; - // This is nn::hid::NpadJoyHoldType enum class NpadJoyHoldType : u64 { Vertical = 0, @@ -133,6 +129,8 @@ public: Revision3 = 3, }; + using SixAxisLifo = Lifo<Core::HID::SixAxisSensorState, hid_entry_count>; + void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); Core::HID::NpadStyleTag GetSupportedStyleSet() const; @@ -185,37 +183,18 @@ public: Result DisconnectNpad(Core::HID::NpadIdType npad_id); - Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::GyroscopeZeroDriftMode drift_mode); - Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::GyroscopeZeroDriftMode& drift_mode) const; - Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool& is_at_rest) const; Result IsFirmwareUpdateAvailableForSixAxisSensor( const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const; - Result EnableSixAxisSensorUnalteredPassthrough( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled); - Result IsSixAxisSensorUnalteredPassthroughEnabled( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const; - Result LoadSixAxisSensorCalibrationParameter( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorCalibrationParameter& calibration) const; - Result GetSixAxisSensorIcInformation( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorIcInformation& ic_information) const; Result ResetIsSixAxisSensorDeviceNewlyAssigned( const Core::HID::SixAxisSensorHandle& sixaxis_handle); - Result SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool sixaxis_status); - Result IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool& is_fusion_enabled) const; - Result SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - bool is_fusion_enabled); - Result SetSixAxisFusionParameters( - const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); - Result GetSixAxisFusionParameters(const Core::HID::SixAxisSensorHandle& sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters& parameters) const; + + SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id); + SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id); + SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id); + SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id); + SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id); + SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id); + Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, bool& is_enabled) const; @@ -239,10 +218,6 @@ public: void ApplyNpadSystemCommonPolicy(); - static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); - static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); - static Result VerifyValidSixAxisSensorHandle( - const Core::HID::SixAxisSensorHandle& device_handle); AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); private: @@ -302,29 +277,6 @@ private: }; static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); - // This is nn::hid::SixAxisSensorAttribute - struct SixAxisSensorAttribute { - union { - u32 raw{}; - BitField<0, 1, u32> is_connected; - BitField<1, 1, u32> is_interpolated; - }; - }; - static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size"); - - // This is nn::hid::SixAxisSensorState - struct SixAxisSensorState { - s64 delta_time{}; - s64 sampling_number{}; - Common::Vec3f accel{}; - Common::Vec3f gyro{}; - Common::Vec3f rotation{}; - std::array<Common::Vec3f, 3> orientation{}; - SixAxisSensorAttribute attribute{}; - INSERT_PADDING_BYTES(4); // Reserved - }; - static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size"); - // This is nn::hid::server::NpadGcTriggerState struct NpadGcTriggerState { s64 sampling_number{}; @@ -444,12 +396,12 @@ private: Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{}; Lifo<NPadGenericState, hid_entry_count> palma_lifo{}; Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{}; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{}; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{}; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{}; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{}; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{}; - Lifo<SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{}; + Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{}; + Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{}; + Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{}; + Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{}; + Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{}; + Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{}; DeviceType device_type{}; INSERT_PADDING_BYTES(0x4); // Reserved NPadSystemProperties system_properties{}; @@ -483,16 +435,6 @@ private: std::chrono::steady_clock::time_point last_vibration_timepoint{}; }; - struct SixaxisParameters { - bool is_fusion_enabled{true}; - bool unaltered_passtrough{false}; - Core::HID::SixAxisSensorFusionParameters fusion{}; - Core::HID::SixAxisSensorCalibrationParameter calibration{}; - Core::HID::SixAxisSensorIcInformation ic_information{}; - Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{ - Core::HID::GyroscopeZeroDriftMode::Standard}; - }; - struct NpadControllerData { Kernel::KEvent* styleset_changed_event{}; NpadInternalState* shared_memory = nullptr; @@ -506,27 +448,10 @@ private: bool is_dual_left_connected{true}; bool is_dual_right_connected{true}; - // Motion parameters - bool sixaxis_at_rest{true}; - bool sixaxis_sensor_enabled{true}; - SixaxisParameters sixaxis_fullkey{}; - SixaxisParameters sixaxis_handheld{}; - SixaxisParameters sixaxis_dual_left{}; - SixaxisParameters sixaxis_dual_right{}; - SixaxisParameters sixaxis_left{}; - SixaxisParameters sixaxis_right{}; - SixaxisParameters sixaxis_unknown{}; - // Current pad state NPadGenericState npad_pad_state{}; NPadGenericState npad_libnx_state{}; NpadGcTriggerState npad_trigger_state{}; - SixAxisSensorState sixaxis_fullkey_state{}; - SixAxisSensorState sixaxis_handheld_state{}; - SixAxisSensorState sixaxis_dual_left_state{}; - SixAxisSensorState sixaxis_dual_right_state{}; - SixAxisSensorState sixaxis_left_lifo_state{}; - SixAxisSensorState sixaxis_right_lifo_state{}; int callback_key{}; }; @@ -537,13 +462,13 @@ private: void WriteEmptyEntry(NpadInternalState* npad); NpadControllerData& GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle); - const NpadControllerData& GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) const; - NpadControllerData& GetControllerFromHandle( const Core::HID::VibrationDeviceHandle& device_handle); const NpadControllerData& GetControllerFromHandle( const Core::HID::VibrationDeviceHandle& device_handle) const; + NpadControllerData& GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle); + const NpadControllerData& GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) const; NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; @@ -551,9 +476,6 @@ private: const Core::HID::SixAxisSensorHandle& device_handle); const Core::HID::SixAxisSensorProperties& GetSixaxisProperties( const Core::HID::SixAxisSensorHandle& device_handle) const; - SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle); - const SixaxisParameters& GetSixaxisState( - const Core::HID::SixAxisSensorHandle& device_handle) const; std::atomic<u64> press_state{}; diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp index 51a18335f..588ff9d62 100644 --- a/src/core/hle/service/hid/controllers/palma.cpp +++ b/src/core/hle/service/hid/controllers/palma.cpp @@ -12,35 +12,35 @@ namespace Service::HID { -Controller_Palma::Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, - KernelHelpers::ServiceContext& service_context_) +Palma::Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, + KernelHelpers::ServiceContext& service_context_) : ControllerBase{hid_core_}, service_context{service_context_} { controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent"); } -Controller_Palma::~Controller_Palma() { +Palma::~Palma() { service_context.CloseEvent(operation_complete_event); }; -void Controller_Palma::OnInit() {} +void Palma::OnInit() {} -void Controller_Palma::OnRelease() {} +void Palma::OnRelease() {} -void Controller_Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { return; } } -Result Controller_Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, - PalmaConnectionHandle& handle) { +Result Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, + PalmaConnectionHandle& handle) { active_handle.npad_id = npad_id; handle = active_handle; return ResultSuccess; } -Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) { +Result Palma::InitializePalma(const PalmaConnectionHandle& handle) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -48,7 +48,7 @@ Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) { return ResultSuccess; } -Kernel::KReadableEvent& Controller_Palma::AcquirePalmaOperationCompleteEvent( +Kernel::KReadableEvent& Palma::AcquirePalmaOperationCompleteEvent( const PalmaConnectionHandle& handle) const { if (handle.npad_id != active_handle.npad_id) { LOG_ERROR(Service_HID, "Invalid npad id {}", handle.npad_id); @@ -56,9 +56,9 @@ Kernel::KReadableEvent& Controller_Palma::AcquirePalmaOperationCompleteEvent( return operation_complete_event->GetReadableEvent(); } -Result Controller_Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle, - PalmaOperationType& operation_type, - PalmaOperationData& data) const { +Result Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle, + PalmaOperationType& operation_type, + PalmaOperationData& data) const { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -67,8 +67,7 @@ Result Controller_Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& hand return ResultSuccess; } -Result Controller_Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, - u64 palma_activity) { +Result Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -79,8 +78,7 @@ Result Controller_Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, return ResultSuccess; } -Result Controller_Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle, - PalmaFrModeType fr_mode_) { +Result Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -88,7 +86,7 @@ Result Controller_Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle, return ResultSuccess; } -Result Controller_Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) { +Result Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -99,25 +97,25 @@ Result Controller_Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) { return ResultSuccess; } -Result Controller_Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) { +Result Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } return ResultSuccess; } -Result Controller_Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) { +Result Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } return ResultSuccess; } -void Controller_Palma::ReadPalmaApplicationSection() {} +void Palma::ReadPalmaApplicationSection() {} -void Controller_Palma::WritePalmaApplicationSection() {} +void Palma::WritePalmaApplicationSection() {} -Result Controller_Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) { +Result Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -128,7 +126,7 @@ Result Controller_Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle return ResultSuccess; } -Result Controller_Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) { +Result Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -139,10 +137,9 @@ Result Controller_Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& return ResultSuccess; } -void Controller_Palma::WritePalmaActivityEntry() {} +void Palma::WritePalmaActivityEntry() {} -Result Controller_Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, - u64 unknown) { +Result Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -153,8 +150,8 @@ Result Controller_Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandl return ResultSuccess; } -Result Controller_Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave, - Common::ProcessAddress t_mem, u64 size) { +Result Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave, + Common::ProcessAddress t_mem, u64 size) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -165,8 +162,8 @@ Result Controller_Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle return ResultSuccess; } -Result Controller_Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle, - s32 database_id_version_) { +Result Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle, + s32 database_id_version_) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -178,8 +175,7 @@ Result Controller_Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnec return ResultSuccess; } -Result Controller_Palma::GetPalmaDataBaseIdentificationVersion( - const PalmaConnectionHandle& handle) { +Result Palma::GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -191,26 +187,26 @@ Result Controller_Palma::GetPalmaDataBaseIdentificationVersion( return ResultSuccess; } -void Controller_Palma::SuspendPalmaFeature() {} +void Palma::SuspendPalmaFeature() {} -Result Controller_Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const { +Result Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } return operation.result; } -void Controller_Palma::ReadPalmaPlayLog() {} +void Palma::ReadPalmaPlayLog() {} -void Controller_Palma::ResetPalmaPlayLog() {} +void Palma::ResetPalmaPlayLog() {} -void Controller_Palma::SetIsPalmaAllConnectable(bool is_all_connectable) { +void Palma::SetIsPalmaAllConnectable(bool is_all_connectable) { // If true controllers are able to be paired is_connectable = is_all_connectable; } -void Controller_Palma::SetIsPalmaPairedConnectable() {} +void Palma::SetIsPalmaPairedConnectable() {} -Result Controller_Palma::PairPalma(const PalmaConnectionHandle& handle) { +Result Palma::PairPalma(const PalmaConnectionHandle& handle) { if (handle.npad_id != active_handle.npad_id) { return InvalidPalmaHandle; } @@ -218,14 +214,14 @@ Result Controller_Palma::PairPalma(const PalmaConnectionHandle& handle) { return ResultSuccess; } -void Controller_Palma::SetPalmaBoostMode(bool boost_mode) {} +void Palma::SetPalmaBoostMode(bool boost_mode) {} -void Controller_Palma::CancelWritePalmaWaveEntry() {} +void Palma::CancelWritePalmaWaveEntry() {} -void Controller_Palma::EnablePalmaBoostMode() {} +void Palma::EnablePalmaBoostMode() {} -void Controller_Palma::GetPalmaBluetoothAddress() {} +void Palma::GetPalmaBluetoothAddress() {} -void Controller_Palma::SetDisallowedPalmaConnection() {} +void Palma::SetDisallowedPalmaConnection() {} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/palma.h b/src/core/hle/service/hid/controllers/palma.h index a0491a819..a6047f36a 100644 --- a/src/core/hle/service/hid/controllers/palma.h +++ b/src/core/hle/service/hid/controllers/palma.h @@ -23,7 +23,7 @@ class EmulatedController; } // namespace Core::HID namespace Service::HID { -class Controller_Palma final : public ControllerBase { +class Palma final : public ControllerBase { public: using PalmaOperationData = std::array<u8, 0x140>; @@ -97,9 +97,9 @@ public: static_assert(sizeof(PalmaConnectionHandle) == 0x8, "PalmaConnectionHandle has incorrect size."); - explicit Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, - KernelHelpers::ServiceContext& service_context_); - ~Controller_Palma() override; + explicit Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, + KernelHelpers::ServiceContext& service_context_); + ~Palma() override; // Called when the controller is initialized void OnInit() override; diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/seven_six_axis.cpp index bcb272eaf..495568484 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/seven_six_axis.cpp @@ -1,32 +1,29 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later +#include <cstring> +#include "common/common_types.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/frontend/emu_window.h" #include "core/hid/emulated_console.h" +#include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/console_sixaxis.h" +#include "core/hle/service/hid/controllers/seven_six_axis.h" #include "core/memory.h" namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; - -Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_) +SevenSixAxis::SevenSixAxis(Core::System& system_) : ControllerBase{system_.HIDCore()}, system{system_} { console = hid_core.GetEmulatedConsole(); - static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size, - "ConsoleSharedMemory is bigger than the shared memory"); - shared_memory = std::construct_at( - reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); } -Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; - -void Controller_ConsoleSixAxis::OnInit() {} +SevenSixAxis::~SevenSixAxis() = default; -void Controller_ConsoleSixAxis::OnRelease() {} +void SevenSixAxis::OnInit() {} +void SevenSixAxis::OnRelease() {} -void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void SevenSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated() || transfer_memory == 0) { seven_sixaxis_lifo.buffer_count = 0; seven_sixaxis_lifo.buffer_tail = 0; @@ -53,22 +50,17 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti -motion_status.quaternion.xyz.z, }; - shared_memory->sampling_number++; - shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; - shared_memory->verticalization_error = motion_status.verticalization_error; - shared_memory->gyro_bias = motion_status.gyro_bias; - - // Update seven six axis transfer memory seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); } -void Controller_ConsoleSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) { +void SevenSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) { transfer_memory = t_mem; } -void Controller_ConsoleSixAxis::ResetTimestamp() { +void SevenSixAxis::ResetTimestamp() { last_saved_timestamp = last_global_timestamp; } + } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/seven_six_axis.h index 7015d924c..40e3f5d12 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/seven_six_axis.h @@ -1,10 +1,9 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include <array> - +#include "common/common_types.h" #include "common/quaternion.h" #include "common/typed_address.h" #include "core/hle/service/hid/controllers/controller_base.h" @@ -19,10 +18,10 @@ class EmulatedConsole; } // namespace Core::HID namespace Service::HID { -class Controller_ConsoleSixAxis final : public ControllerBase { +class SevenSixAxis final : public ControllerBase { public: - explicit Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_); - ~Controller_ConsoleSixAxis() override; + explicit SevenSixAxis(Core::System& system_); + ~SevenSixAxis() override; // Called when the controller is initialized void OnInit() override; @@ -51,28 +50,16 @@ private: }; static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size"); - // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat - struct ConsoleSharedMemory { - u64 sampling_number{}; - bool is_seven_six_axis_sensor_at_rest{}; - INSERT_PADDING_BYTES(3); // padding - f32 verticalization_error{}; - Common::Vec3f gyro_bias{}; - INSERT_PADDING_BYTES(4); // padding - }; - static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); - Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); + u64 last_saved_timestamp{}; + u64 last_global_timestamp{}; + SevenSixAxisState next_seven_sixaxis_state{}; Common::ProcessAddress transfer_memory{}; - ConsoleSharedMemory* shared_memory = nullptr; Core::HID::EmulatedConsole* console = nullptr; - u64 last_saved_timestamp{}; - u64 last_global_timestamp{}; - Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/six_axis.cpp b/src/core/hle/service/hid/controllers/six_axis.cpp new file mode 100644 index 000000000..3d24a5c04 --- /dev/null +++ b/src/core/hle/service/hid/controllers/six_axis.cpp @@ -0,0 +1,413 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "common/common_types.h" +#include "core/core_timing.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/controllers/six_axis.h" +#include "core/hle/service/hid/errors.h" +#include "core/hle/service/hid/hid_util.h" + +namespace Service::HID { + +SixAxis::SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_) + : ControllerBase{hid_core_}, npad{npad_} { + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + controller.device = hid_core.GetEmulatedControllerByIndex(i); + } +} + +SixAxis::~SixAxis() = default; + +void SixAxis::OnInit() {} +void SixAxis::OnRelease() {} + +void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { + if (!IsControllerActivated()) { + return; + } + + for (std::size_t i = 0; i < controller_data.size(); ++i) { + auto& controller = controller_data[i]; + + const auto npad_id = IndexToNpadIdType(i); + const auto& controller_type = controller.device->GetNpadStyleIndex(); + + if (controller_type == Core::HID::NpadStyleIndex::None || + !controller.device->IsConnected()) { + continue; + } + + const auto& motion_state = controller.device->GetMotions(); + auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; + auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; + auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state; + auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state; + auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; + auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; + + auto& sixaxis_fullkey_lifo = npad->GetSixAxisFullkeyLifo(npad_id); + auto& sixaxis_handheld_lifo = npad->GetSixAxisHandheldLifo(npad_id); + auto& sixaxis_dual_left_lifo = npad->GetSixAxisDualLeftLifo(npad_id); + auto& sixaxis_dual_right_lifo = npad->GetSixAxisDualRightLifo(npad_id); + auto& sixaxis_left_lifo = npad->GetSixAxisLeftLifo(npad_id); + auto& sixaxis_right_lifo = npad->GetSixAxisRightLifo(npad_id); + + // Clear previous state + sixaxis_fullkey_state = {}; + sixaxis_handheld_state = {}; + sixaxis_dual_left_state = {}; + sixaxis_dual_right_state = {}; + sixaxis_left_lifo_state = {}; + sixaxis_right_lifo_state = {}; + + if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { + controller.sixaxis_at_rest = true; + for (std::size_t e = 0; e < motion_state.size(); ++e) { + controller.sixaxis_at_rest = + controller.sixaxis_at_rest && motion_state[e].is_at_rest; + } + } + + const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state, + const Core::HID::ControllerMotion& hid_state) { + using namespace std::literals::chrono_literals; + static constexpr Core::HID::SixAxisSensorState default_motion_state = { + .delta_time = std::chrono::nanoseconds(5ms).count(), + .accel = {0, 0, -1.0f}, + .orientation = + { + Common::Vec3f{1.0f, 0, 0}, + Common::Vec3f{0, 1.0f, 0}, + Common::Vec3f{0, 0, 1.0f}, + }, + .attribute = {1}, + }; + if (!controller.sixaxis_sensor_enabled) { + state = default_motion_state; + return; + } + if (!Settings::values.motion_enabled.GetValue()) { + state = default_motion_state; + return; + } + state.attribute.is_connected.Assign(1); + state.delta_time = std::chrono::nanoseconds(5ms).count(); + state.accel = hid_state.accel; + state.gyro = hid_state.gyro; + state.rotation = hid_state.rotation; + state.orientation = hid_state.orientation; + }; + + switch (controller_type) { + case Core::HID::NpadStyleIndex::None: + ASSERT(false); + break; + case Core::HID::NpadStyleIndex::ProController: + set_motion_state(sixaxis_fullkey_state, motion_state[0]); + break; + case Core::HID::NpadStyleIndex::Handheld: + set_motion_state(sixaxis_handheld_state, motion_state[0]); + break; + case Core::HID::NpadStyleIndex::JoyconDual: + set_motion_state(sixaxis_dual_left_state, motion_state[0]); + set_motion_state(sixaxis_dual_right_state, motion_state[1]); + break; + case Core::HID::NpadStyleIndex::JoyconLeft: + set_motion_state(sixaxis_left_lifo_state, motion_state[0]); + break; + case Core::HID::NpadStyleIndex::JoyconRight: + set_motion_state(sixaxis_right_lifo_state, motion_state[1]); + break; + case Core::HID::NpadStyleIndex::Pokeball: + using namespace std::literals::chrono_literals; + set_motion_state(sixaxis_fullkey_state, motion_state[0]); + sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count(); + break; + default: + break; + } + + sixaxis_fullkey_state.sampling_number = + sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_handheld_state.sampling_number = + sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_dual_left_state.sampling_number = + sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_dual_right_state.sampling_number = + sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_left_lifo_state.sampling_number = + sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_right_lifo_state.sampling_number = + sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + + if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { + // This buffer only is updated on handheld on HW + sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); + } else { + // Handheld doesn't update this buffer on HW + sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); + } + + sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); + sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); + sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); + sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); + } +} + +Result SixAxis::SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::GyroscopeZeroDriftMode drift_mode) { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + auto& sixaxis = GetSixaxisState(sixaxis_handle); + auto& controller = GetControllerFromHandle(sixaxis_handle); + sixaxis.gyroscope_zero_drift_mode = drift_mode; + controller.device->SetGyroscopeZeroDriftMode(drift_mode); + + return ResultSuccess; +} + +Result SixAxis::GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::GyroscopeZeroDriftMode& drift_mode) const { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + const auto& sixaxis = GetSixaxisState(sixaxis_handle); + drift_mode = sixaxis.gyroscope_zero_drift_mode; + + return ResultSuccess; +} + +Result SixAxis::IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + bool& is_at_rest) const { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + const auto& controller = GetControllerFromHandle(sixaxis_handle); + is_at_rest = controller.sixaxis_at_rest; + return ResultSuccess; +} + +Result SixAxis::LoadSixAxisSensorCalibrationParameter( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::SixAxisSensorCalibrationParameter& calibration) const { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + // TODO: Request this data to the controller. On error return 0xd8ca + const auto& sixaxis = GetSixaxisState(sixaxis_handle); + calibration = sixaxis.calibration; + return ResultSuccess; +} + +Result SixAxis::GetSixAxisSensorIcInformation( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::SixAxisSensorIcInformation& ic_information) const { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + // TODO: Request this data to the controller. On error return 0xd8ca + const auto& sixaxis = GetSixaxisState(sixaxis_handle); + ic_information = sixaxis.ic_information; + return ResultSuccess; +} + +Result SixAxis::EnableSixAxisSensorUnalteredPassthrough( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + auto& sixaxis = GetSixaxisState(sixaxis_handle); + sixaxis.unaltered_passtrough = is_enabled; + return ResultSuccess; +} + +Result SixAxis::IsSixAxisSensorUnalteredPassthroughEnabled( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + const auto& sixaxis = GetSixaxisState(sixaxis_handle); + is_enabled = sixaxis.unaltered_passtrough; + return ResultSuccess; +} + +Result SixAxis::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + bool sixaxis_status) { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + auto& controller = GetControllerFromHandle(sixaxis_handle); + controller.sixaxis_sensor_enabled = sixaxis_status; + return ResultSuccess; +} + +Result SixAxis::IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + bool& is_fusion_enabled) const { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + const auto& sixaxis = GetSixaxisState(sixaxis_handle); + is_fusion_enabled = sixaxis.is_fusion_enabled; + + return ResultSuccess; +} +Result SixAxis::SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + bool is_fusion_enabled) { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + auto& sixaxis = GetSixaxisState(sixaxis_handle); + sixaxis.is_fusion_enabled = is_fusion_enabled; + + return ResultSuccess; +} + +Result SixAxis::SetSixAxisFusionParameters( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + const auto param1 = sixaxis_fusion_parameters.parameter1; + if (param1 < 0.0f || param1 > 1.0f) { + return InvalidSixAxisFusionRange; + } + + auto& sixaxis = GetSixaxisState(sixaxis_handle); + sixaxis.fusion = sixaxis_fusion_parameters; + + return ResultSuccess; +} + +Result SixAxis::GetSixAxisFusionParameters( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::SixAxisSensorFusionParameters& parameters) const { + const auto is_valid = IsSixaxisHandleValid(sixaxis_handle); + if (is_valid.IsError()) { + LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); + return is_valid; + } + + const auto& sixaxis = GetSixaxisState(sixaxis_handle); + parameters = sixaxis.fusion; + + return ResultSuccess; +} + +SixAxis::SixaxisParameters& SixAxis::GetSixaxisState( + const Core::HID::SixAxisSensorHandle& sixaxis_handle) { + auto& controller = GetControllerFromHandle(sixaxis_handle); + switch (sixaxis_handle.npad_type) { + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Pokeball: + return controller.sixaxis_fullkey; + case Core::HID::NpadStyleIndex::Handheld: + return controller.sixaxis_handheld; + case Core::HID::NpadStyleIndex::JoyconDual: + if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { + return controller.sixaxis_dual_left; + } + return controller.sixaxis_dual_right; + case Core::HID::NpadStyleIndex::JoyconLeft: + return controller.sixaxis_left; + case Core::HID::NpadStyleIndex::JoyconRight: + return controller.sixaxis_right; + default: + return controller.sixaxis_unknown; + } +} + +const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState( + const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { + const auto& controller = GetControllerFromHandle(sixaxis_handle); + switch (sixaxis_handle.npad_type) { + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Pokeball: + return controller.sixaxis_fullkey; + case Core::HID::NpadStyleIndex::Handheld: + return controller.sixaxis_handheld; + case Core::HID::NpadStyleIndex::JoyconDual: + if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) { + return controller.sixaxis_dual_left; + } + return controller.sixaxis_dual_right; + case Core::HID::NpadStyleIndex::JoyconLeft: + return controller.sixaxis_left; + case Core::HID::NpadStyleIndex::JoyconRight: + return controller.sixaxis_right; + default: + return controller.sixaxis_unknown; + } +} + +SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) { + const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +const SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) const { + const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); + return GetControllerFromNpadIdType(npad_id); +} + +SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + npad_id = Core::HID::NpadIdType::Player1; + } + const auto npad_index = NpadIdTypeToIndex(npad_id); + return controller_data[npad_index]; +} + +const SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType( + Core::HID::NpadIdType npad_id) const { + if (!IsNpadIdValid(npad_id)) { + LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); + npad_id = Core::HID::NpadIdType::Player1; + } + const auto npad_index = NpadIdTypeToIndex(npad_id); + return controller_data[npad_index]; +} + +} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/six_axis.h b/src/core/hle/service/hid/controllers/six_axis.h new file mode 100644 index 000000000..4c4f5dc7b --- /dev/null +++ b/src/core/hle/service/hid/controllers/six_axis.h @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hid/hid_types.h" +#include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Core::HID { +class EmulatedController; +} // namespace Core::HID + +namespace Service::HID { +class NPad; + +class SixAxis final : public ControllerBase { +public: + explicit SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_); + ~SixAxis() override; + + // Called when the controller is initialized + void OnInit() override; + + // When the controller is released + void OnRelease() override; + + // When the controller is requesting an update for the shared memory + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; + + Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::GyroscopeZeroDriftMode drift_mode); + Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::GyroscopeZeroDriftMode& drift_mode) const; + Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + bool& is_at_rest) const; + Result EnableSixAxisSensorUnalteredPassthrough( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled); + Result IsSixAxisSensorUnalteredPassthroughEnabled( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const; + Result LoadSixAxisSensorCalibrationParameter( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::SixAxisSensorCalibrationParameter& calibration) const; + Result GetSixAxisSensorIcInformation( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::SixAxisSensorIcInformation& ic_information) const; + Result SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + bool sixaxis_status); + Result IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + bool& is_fusion_enabled) const; + Result SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + bool is_fusion_enabled); + Result SetSixAxisFusionParameters( + const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); + Result GetSixAxisFusionParameters(const Core::HID::SixAxisSensorHandle& sixaxis_handle, + Core::HID::SixAxisSensorFusionParameters& parameters) const; + +private: + static constexpr std::size_t NPAD_COUNT = 10; + + struct SixaxisParameters { + bool is_fusion_enabled{true}; + bool unaltered_passtrough{false}; + Core::HID::SixAxisSensorFusionParameters fusion{}; + Core::HID::SixAxisSensorCalibrationParameter calibration{}; + Core::HID::SixAxisSensorIcInformation ic_information{}; + Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{ + Core::HID::GyroscopeZeroDriftMode::Standard}; + }; + + struct NpadControllerData { + Core::HID::EmulatedController* device = nullptr; + + // Motion parameters + bool sixaxis_at_rest{true}; + bool sixaxis_sensor_enabled{true}; + SixaxisParameters sixaxis_fullkey{}; + SixaxisParameters sixaxis_handheld{}; + SixaxisParameters sixaxis_dual_left{}; + SixaxisParameters sixaxis_dual_right{}; + SixaxisParameters sixaxis_left{}; + SixaxisParameters sixaxis_right{}; + SixaxisParameters sixaxis_unknown{}; + + // Current pad state + Core::HID::SixAxisSensorState sixaxis_fullkey_state{}; + Core::HID::SixAxisSensorState sixaxis_handheld_state{}; + Core::HID::SixAxisSensorState sixaxis_dual_left_state{}; + Core::HID::SixAxisSensorState sixaxis_dual_right_state{}; + Core::HID::SixAxisSensorState sixaxis_left_lifo_state{}; + Core::HID::SixAxisSensorState sixaxis_right_lifo_state{}; + int callback_key{}; + }; + + SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle); + const SixaxisParameters& GetSixaxisState( + const Core::HID::SixAxisSensorHandle& device_handle) const; + + NpadControllerData& GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle); + const NpadControllerData& GetControllerFromHandle( + const Core::HID::SixAxisSensorHandle& device_handle) const; + NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); + const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; + + std::shared_ptr<NPad> npad; + std::array<NpadControllerData, NPAD_COUNT> controller_data{}; +}; +} // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 3ef91df4b..3bcf0ee9f 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -15,8 +15,7 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_, - u8* raw_shared_memory_) +TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} { static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size, "TouchSharedMemory is bigger than the shared memory"); @@ -25,13 +24,13 @@ Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_, console = hid_core.GetEmulatedConsole(); } -Controller_Touchscreen::~Controller_Touchscreen() = default; +TouchScreen::~TouchScreen() = default; -void Controller_Touchscreen::OnInit() {} +void TouchScreen::OnInit() {} -void Controller_Touchscreen::OnRelease() {} +void TouchScreen::OnRelease() {} -void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); if (!IsControllerActivated()) { diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index dd00921fd..cd342ce91 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -14,10 +14,10 @@ class EmulatedConsole; } // namespace Core::HID namespace Service::HID { -class Controller_Touchscreen final : public ControllerBase { +class TouchScreen final : public ControllerBase { public: - explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); - ~Controller_Touchscreen() override; + explicit TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + ~TouchScreen() override; // Called when the controller is initialized void OnInit() override; diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 62119e2c5..0aaed1fa7 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -10,20 +10,19 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; -Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) - : ControllerBase{hid_core_} { +XPad::XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} { static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size, "XpadSharedMemory is bigger than the shared memory"); shared_memory = std::construct_at( reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); } -Controller_XPad::~Controller_XPad() = default; +XPad::~XPad() = default; -void Controller_XPad::OnInit() {} +void XPad::OnInit() {} -void Controller_XPad::OnRelease() {} +void XPad::OnRelease() {} -void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { +void XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { shared_memory->basic_xpad_lifo.buffer_count = 0; shared_memory->basic_xpad_lifo.buffer_tail = 0; diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index d01dee5fc..9e63a317a 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -10,10 +10,10 @@ #include "core/hle/service/hid/ring_lifo.h" namespace Service::HID { -class Controller_XPad final : public ControllerBase { +class XPad final : public ControllerBase { public: - explicit Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); - ~Controller_XPad() override; + explicit XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + ~XPad() override; // Called when the controller is initialized void OnInit() override; diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index 9caed6541..583142e35 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp @@ -12,11 +12,12 @@ #include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/hid_firmware_settings.h" #include "core/hle/service/hid/hid_server.h" +#include "core/hle/service/hid/hid_util.h" #include "core/hle/service/hid/resource_manager.h" #include "core/hle/service/ipc_helpers.h" #include "core/memory.h" -#include "core/hle/service/hid/controllers/console_sixaxis.h" +#include "core/hle/service/hid/controllers/console_six_axis.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/debug_pad.h" #include "core/hle/service/hid/controllers/gesture.h" @@ -24,9 +25,9 @@ #include "core/hle/service/hid/controllers/mouse.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/palma.h" -#include "core/hle/service/hid/controllers/stubbed.h" +#include "core/hle/service/hid/controllers/seven_six_axis.h" +#include "core/hle/service/hid/controllers/six_axis.h" #include "core/hle/service/hid/controllers/touchscreen.h" -#include "core/hle/service/hid/controllers/xpad.h" namespace Service::HID { @@ -50,8 +51,7 @@ private: const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; if (resource_manager != nullptr) { - resource_manager->GetController<Controller_NPad>(HidController::NPad) - .InitializeVibrationDevice(vibration_device_handle); + resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle); } LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}", @@ -235,15 +235,14 @@ void IHidServer::ActivateDebugPad(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); Result result = ResultSuccess; - auto& debug_pad = - GetResourceManager()->GetController<Controller_DebugPad>(HidController::DebugPad); + auto debug_pad = GetResourceManager()->GetDebugPad(); if (!firmware_settings->IsDeviceManaged()) { - result = debug_pad.Activate(); + result = debug_pad->Activate(); } if (result.IsSuccess()) { - result = debug_pad.Activate(applet_resource_user_id); + result = debug_pad->Activate(applet_resource_user_id); } IPC::ResponseBuilder rb{ctx, 2}; @@ -257,15 +256,14 @@ void IHidServer::ActivateTouchScreen(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); Result result = ResultSuccess; - auto& touch_screen = - GetResourceManager()->GetController<Controller_Touchscreen>(HidController::Touchscreen); + auto touch_screen = GetResourceManager()->GetTouchScreen(); if (!firmware_settings->IsDeviceManaged()) { - result = touch_screen.Activate(); + result = touch_screen->Activate(); } if (result.IsSuccess()) { - result = touch_screen.Activate(applet_resource_user_id); + result = touch_screen->Activate(applet_resource_user_id); } IPC::ResponseBuilder rb{ctx, 2}; @@ -279,14 +277,14 @@ void IHidServer::ActivateMouse(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); Result result = ResultSuccess; - auto& mouse = GetResourceManager()->GetController<Controller_Mouse>(HidController::Mouse); + auto mouse = GetResourceManager()->GetMouse(); if (!firmware_settings->IsDeviceManaged()) { - result = mouse.Activate(); + result = mouse->Activate(); } if (result.IsSuccess()) { - result = mouse.Activate(applet_resource_user_id); + result = mouse->Activate(applet_resource_user_id); } IPC::ResponseBuilder rb{ctx, 2}; @@ -300,15 +298,14 @@ void IHidServer::ActivateKeyboard(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); Result result = ResultSuccess; - auto& keyboard = - GetResourceManager()->GetController<Controller_Keyboard>(HidController::Keyboard); + auto keyboard = GetResourceManager()->GetKeyboard(); if (!firmware_settings->IsDeviceManaged()) { - result = keyboard.Activate(); + result = keyboard->Activate(); } if (result.IsSuccess()) { - result = keyboard.Activate(applet_resource_user_id); + result = keyboard->Activate(applet_resource_user_id); } IPC::ResponseBuilder rb{ctx, 2}; @@ -502,8 +499,8 @@ void IHidServer::StartSixAxisSensor(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, true); + auto six_axis = GetResourceManager()->GetSixAxis(); + const auto result = six_axis->SetSixAxisEnabled(parameters.sixaxis_handle, true); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -525,8 +522,8 @@ void IHidServer::StopSixAxisSensor(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, false); + auto six_axis = GetResourceManager()->GetSixAxis(); + const auto result = six_axis->SetSixAxisEnabled(parameters.sixaxis_handle, false); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -549,9 +546,9 @@ void IHidServer::IsSixAxisSensorFusionEnabled(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; bool is_enabled{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto six_axis = GetResourceManager()->GetSixAxis(); const auto result = - controller.IsSixAxisSensorFusionEnabled(parameters.sixaxis_handle, is_enabled); + six_axis->IsSixAxisSensorFusionEnabled(parameters.sixaxis_handle, is_enabled); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -575,9 +572,9 @@ void IHidServer::EnableSixAxisSensorFusion(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle, - parameters.enable_sixaxis_sensor_fusion); + auto six_axis = GetResourceManager()->GetSixAxis(); + const auto result = six_axis->SetSixAxisFusionEnabled(parameters.sixaxis_handle, + parameters.enable_sixaxis_sensor_fusion); LOG_DEBUG(Service_HID, "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " @@ -602,9 +599,9 @@ void IHidServer::SetSixAxisSensorFusionParameters(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto six_axis = GetResourceManager()->GetSixAxis(); const auto result = - controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion); + six_axis->SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " @@ -629,10 +626,9 @@ void IHidServer::GetSixAxisSensorFusionParameters(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; Core::HID::SixAxisSensorFusionParameters fusion_parameters{}; - const auto& controller = - GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto six_axis = GetResourceManager()->GetSixAxis(); const auto result = - controller.GetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters); + six_axis->GetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -660,10 +656,10 @@ void IHidServer::ResetSixAxisSensorFusionParameters(HLERequestContext& ctx) { .parameter1 = 0.03f, .parameter2 = 0.4f, }; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto six_axis = GetResourceManager()->GetSixAxis(); const auto result1 = - controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters); - const auto result2 = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle, true); + six_axis->SetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters); + const auto result2 = six_axis->SetSixAxisFusionEnabled(parameters.sixaxis_handle, true); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -684,8 +680,8 @@ void IHidServer::SetGyroscopeZeroDriftMode(HLERequestContext& ctx) { const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode); + auto six_axis = GetResourceManager()->GetSixAxis(); + const auto result = six_axis->SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " @@ -709,8 +705,8 @@ void IHidServer::GetGyroscopeZeroDriftMode(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); + auto six_axis = GetResourceManager()->GetSixAxis(); + const auto result = six_axis->GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -734,8 +730,8 @@ void IHidServer::ResetGyroscopeZeroDriftMode(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); + auto six_axis = GetResourceManager()->GetSixAxis(); + const auto result = six_axis->SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -758,8 +754,8 @@ void IHidServer::IsSixAxisSensorAtRest(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; bool is_at_rest{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest); + auto six_axis = GetResourceManager()->GetSixAxis(); + six_axis->IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -783,9 +779,9 @@ void IHidServer::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ct const auto parameters{rp.PopRaw<Parameters>()}; bool is_firmware_available{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle, - is_firmware_available); + auto controller = GetResourceManager()->GetNpad(); + controller->IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle, + is_firmware_available); LOG_WARNING( Service_HID, @@ -809,9 +805,9 @@ void IHidServer::EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx) const auto parameters{rp.PopRaw<Parameters>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.EnableSixAxisSensorUnalteredPassthrough( - parameters.sixaxis_handle, parameters.enabled); + auto six_axis = GetResourceManager()->GetSixAxis(); + const auto result = six_axis->EnableSixAxisSensorUnalteredPassthrough(parameters.sixaxis_handle, + parameters.enabled); LOG_DEBUG(Service_HID, "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, " @@ -836,8 +832,8 @@ void IHidServer::IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& c const auto parameters{rp.PopRaw<Parameters>()}; bool is_unaltered_sisxaxis_enabled{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled( + auto six_axis = GetResourceManager()->GetSixAxis(); + const auto result = six_axis->IsSixAxisSensorUnalteredPassthroughEnabled( parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled); LOG_DEBUG( @@ -863,9 +859,9 @@ void IHidServer::LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; Core::HID::SixAxisSensorCalibrationParameter calibration{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto six_axis = GetResourceManager()->GetSixAxis(); const auto result = - controller.LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration); + six_axis->LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration); LOG_WARNING( Service_HID, @@ -893,9 +889,9 @@ void IHidServer::GetSixAxisSensorIcInformation(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; Core::HID::SixAxisSensorIcInformation ic_information{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto six_axis = GetResourceManager()->GetSixAxis(); const auto result = - controller.GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information); + six_axis->GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information); LOG_WARNING( Service_HID, @@ -922,9 +918,9 @@ void IHidServer::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx) const auto parameters{rp.PopRaw<Parameters>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto controller = GetResourceManager()->GetNpad(); const auto result = - controller.ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle); + controller->ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle); LOG_WARNING( Service_HID, @@ -951,15 +947,15 @@ void IHidServer::ActivateGesture(HLERequestContext& ctx) { parameters.basic_gesture_id, parameters.applet_resource_user_id); Result result = ResultSuccess; - auto& gesture = GetResourceManager()->GetController<Controller_Gesture>(HidController::Gesture); + auto gesture = GetResourceManager()->GetGesture(); if (!firmware_settings->IsDeviceManaged()) { - result = gesture.Activate(); + result = gesture->Activate(); } if (result.IsSuccess()) { // TODO: Use gesture id here - result = gesture.Activate(parameters.applet_resource_user_id); + result = gesture->Activate(parameters.applet_resource_user_id); } IPC::ResponseBuilder rb{ctx, 2}; @@ -977,9 +973,7 @@ void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SetSupportedStyleSet({parameters.supported_styleset}); + GetResourceManager()->GetNpad()->SetSupportedStyleSet({parameters.supported_styleset}); LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}", parameters.supported_styleset, parameters.applet_resource_user_id); @@ -996,19 +990,14 @@ void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetSupportedStyleSet() - .raw); + rb.PushEnum(GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw); } void IHidServer::SetSupportedNpadIdType(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto result = GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SetSupportedNpadIdTypes(ctx.ReadBuffer()); + const auto result = GetResourceManager()->GetNpad()->SetSupportedNpadIdTypes(ctx.ReadBuffer()); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); @@ -1022,10 +1011,10 @@ void IHidServer::ActivateNpad(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); - auto& npad = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto npad = GetResourceManager()->GetNpad(); // TODO: npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0); - const Result result = npad.Activate(applet_resource_user_id); + const Result result = npad->Activate(applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -1059,15 +1048,12 @@ void IHidServer::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) { parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown); // Games expect this event to be signaled after calling this function - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SignalStyleSetChangedEvent(parameters.npad_id); + GetResourceManager()->GetNpad()->SignalStyleSetChangedEvent(parameters.npad_id); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetStyleSetChangedEvent(parameters.npad_id)); + rb.PushCopyObjects( + GetResourceManager()->GetNpad()->GetStyleSetChangedEvent(parameters.npad_id)); } void IHidServer::DisconnectNpad(HLERequestContext& ctx) { @@ -1081,8 +1067,8 @@ void IHidServer::DisconnectNpad(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - controller.DisconnectNpad(parameters.npad_id); + auto controller = GetResourceManager()->GetNpad(); + controller->DisconnectNpad(parameters.npad_id); LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1096,8 +1082,8 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) { const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; Core::HID::LedPattern pattern{0, 0, 0, 0}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.GetLedPattern(npad_id, pattern); + auto controller = GetResourceManager()->GetNpad(); + const auto result = controller->GetLedPattern(npad_id, pattern); LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); @@ -1109,7 +1095,7 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) { void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Controller_NPad::NpadRevision revision; + NPad::NpadRevision revision; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -1120,10 +1106,10 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision, parameters.applet_resource_user_id); - auto& npad = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto npad = GetResourceManager()->GetNpad(); // TODO: npad->SetRevision(applet_resource_user_id, revision); - const auto result = npad.Activate(parameters.applet_resource_user_id); + const auto result = npad->Activate(parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -1132,11 +1118,9 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()}; + const auto hold_type{rp.PopEnum<NPad::NpadJoyHoldType>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SetHoldType(hold_type); + GetResourceManager()->GetNpad()->SetHoldType(hold_type); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", applet_resource_user_id, hold_type); @@ -1153,8 +1137,7 @@ void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushEnum( - GetResourceManager()->GetController<Controller_NPad>(HidController::NPad).GetHoldType()); + rb.PushEnum(GetResourceManager()->GetNpad()->GetHoldType()); } void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) { @@ -1169,10 +1152,9 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) const auto parameters{rp.PopRaw<Parameters>()}; Core::HID::NpadIdType new_npad_id{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(new_npad_id, parameters.npad_id, - Controller_NPad::NpadJoyDeviceType::Left, - Controller_NPad::NpadJoyAssignmentMode::Single); + auto controller = GetResourceManager()->GetNpad(); + controller->SetNpadMode(new_npad_id, parameters.npad_id, NPad::NpadJoyDeviceType::Left, + NPad::NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1187,16 +1169,16 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) { Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - Controller_NPad::NpadJoyDeviceType npad_joy_device_type; + NPad::NpadJoyDeviceType npad_joy_device_type; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; Core::HID::NpadIdType new_npad_id{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, - Controller_NPad::NpadJoyAssignmentMode::Single); + auto controller = GetResourceManager()->GetNpad(); + controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, + NPad::NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", parameters.npad_id, parameters.applet_resource_user_id, @@ -1218,9 +1200,8 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; Core::HID::NpadIdType new_npad_id{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - controller.SetNpadMode(new_npad_id, parameters.npad_id, {}, - Controller_NPad::NpadJoyAssignmentMode::Dual); + auto controller = GetResourceManager()->GetNpad(); + controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NPad::NpadJoyAssignmentMode::Dual); LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); // Spams a lot when controller applet is open @@ -1235,8 +1216,8 @@ void IHidServer::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) { const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); + auto controller = GetResourceManager()->GetNpad(); + const auto result = controller->MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", npad_id_1, npad_id_2, applet_resource_user_id); @@ -1249,9 +1230,7 @@ void IHidServer::StartLrAssignmentMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .StartLRAssignmentMode(); + GetResourceManager()->GetNpad()->StartLRAssignmentMode(); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); @@ -1263,9 +1242,7 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .StopLRAssignmentMode(); + GetResourceManager()->GetNpad()->StopLRAssignmentMode(); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); @@ -1276,11 +1253,9 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) { void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()}; + const auto activation_mode{rp.PopEnum<NPad::NpadHandheldActivationMode>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SetNpadHandheldActivationMode(activation_mode); + GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}", applet_resource_user_id, activation_mode); @@ -1297,9 +1272,7 @@ void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushEnum(GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetNpadHandheldActivationMode()); + rb.PushEnum(GetResourceManager()->GetNpad()->GetNpadHandheldActivationMode()); } void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) { @@ -1308,8 +1281,8 @@ void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) { const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; const auto applet_resource_user_id{rp.Pop<u64>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.SwapNpadAssignment(npad_id_1, npad_id_2); + auto controller = GetResourceManager()->GetNpad(); + const auto result = controller->SwapNpadAssignment(npad_id_1, npad_id_2); LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", npad_id_1, npad_id_2, applet_resource_user_id); @@ -1330,9 +1303,9 @@ void IHidServer::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& const auto parameters{rp.PopRaw<Parameters>()}; bool is_enabled = false; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto controller = GetResourceManager()->GetNpad(); const auto result = - controller.IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled); + controller->IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled); LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1354,8 +1327,8 @@ void IHidServer::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ct const auto parameters{rp.PopRaw<Parameters>()}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); - const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled( + auto controller = GetResourceManager()->GetNpad(); + const auto result = controller->SetUnintendedHomeButtonInputProtectionEnabled( parameters.is_enabled, parameters.npad_id); LOG_DEBUG(Service_HID, @@ -1372,17 +1345,17 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - Controller_NPad::NpadJoyDeviceType npad_joy_device_type; + NPad::NpadJoyDeviceType npad_joy_device_type; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); const auto parameters{rp.PopRaw<Parameters>()}; Core::HID::NpadIdType new_npad_id{}; - auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + auto controller = GetResourceManager()->GetNpad(); const auto is_reassigned = - controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, - Controller_NPad::NpadJoyAssignmentMode::Single); + controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, + NPad::NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", parameters.npad_id, parameters.applet_resource_user_id, @@ -1405,9 +1378,8 @@ void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp); + GetResourceManager()->GetNpad()->SetAnalogStickUseCenterClamp( + parameters.analog_stick_use_center_clamp); LOG_WARNING(Service_HID, "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}", @@ -1451,8 +1423,7 @@ void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) { void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; - const auto& controller = - GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); + const auto controller = GetResourceManager()->GetNpad(); Core::HID::VibrationDeviceInfo vibration_device_info; bool check_device_index = false; @@ -1496,7 +1467,7 @@ void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", vibration_device_info.type, vibration_device_info.position); - const auto result = controller.IsDeviceHandleValid(vibration_device_handle); + const auto result = IsVibrationHandleValid(vibration_device_handle); if (result.IsError()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -1520,9 +1491,8 @@ void IHidServer::SendVibrationValue(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .VibrateController(parameters.vibration_device_handle, parameters.vibration_value); + GetResourceManager()->GetNpad()->VibrateController(parameters.vibration_device_handle, + parameters.vibration_value); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -1553,9 +1523,8 @@ void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); - rb.PushRaw(GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetLastVibration(parameters.vibration_device_handle)); + rb.PushRaw( + GetResourceManager()->GetNpad()->GetLastVibration(parameters.vibration_device_handle)); } void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) { @@ -1606,9 +1575,7 @@ void IHidServer::SendVibrationValues(HLERequestContext& ctx) { auto vibration_values = std::span( reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count); - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .VibrateControllers(vibration_device_handles, vibration_values); + GetResourceManager()->GetNpad()->VibrateControllers(vibration_device_handles, vibration_values); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); @@ -1662,9 +1629,8 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { } }(); - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .VibrateController(parameters.vibration_device_handle, vibration_value); + GetResourceManager()->GetNpad()->VibrateController(parameters.vibration_device_handle, + vibration_value); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " @@ -1688,9 +1654,8 @@ void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) { const auto parameters{rp.PopRaw<Parameters>()}; - const auto last_vibration = GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetLastVibration(parameters.vibration_device_handle); + const auto last_vibration = + GetResourceManager()->GetNpad()->GetLastVibration(parameters.vibration_device_handle); const auto gc_erm_command = [last_vibration] { if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { @@ -1725,9 +1690,7 @@ void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SetPermitVibrationSession(true); + GetResourceManager()->GetNpad()->SetPermitVibrationSession(true); LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); @@ -1736,9 +1699,7 @@ void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) { } void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) { - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SetPermitVibrationSession(false); + GetResourceManager()->GetNpad()->SetPermitVibrationSession(false); LOG_DEBUG(Service_HID, "called"); @@ -1765,9 +1726,8 @@ void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .IsVibrationDeviceMounted(parameters.vibration_device_handle)); + rb.Push(GetResourceManager()->GetNpad()->IsVibrationDeviceMounted( + parameters.vibration_device_handle)); } void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { @@ -1777,15 +1737,14 @@ void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); Result result = ResultSuccess; - auto console_sixaxis = GetResourceManager()->GetController<Controller_ConsoleSixAxis>( - HidController::ConsoleSixAxisSensor); + auto console_sixaxis = GetResourceManager()->GetConsoleSixAxis(); if (!firmware_settings->IsDeviceManaged()) { - result = console_sixaxis.Activate(); + result = console_sixaxis->Activate(); } if (result.IsSuccess()) { - result = console_sixaxis.Activate(applet_resource_user_id); + result = console_sixaxis->Activate(applet_resource_user_id); } IPC::ResponseBuilder rb{ctx, 2}; @@ -1839,15 +1798,14 @@ void IHidServer::ActivateSevenSixAxisSensor(HLERequestContext& ctx) { LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); Result result = ResultSuccess; - auto console_sixaxis = GetResourceManager()->GetController<Controller_ConsoleSixAxis>( - HidController::ConsoleSixAxisSensor); + auto seven_sixaxis = GetResourceManager()->GetSevenSixAxis(); if (!firmware_settings->IsDeviceManaged()) { - result = console_sixaxis.Activate(); + result = seven_sixaxis->Activate(); } if (result.IsSuccess()) { - console_sixaxis.Activate(applet_resource_user_id); + seven_sixaxis->Activate(applet_resource_user_id); } IPC::ResponseBuilder rb{ctx, 2}; @@ -1911,13 +1869,10 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) { ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size"); // Activate console six axis controller - GetResourceManager() - ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor) - .Activate(); + GetResourceManager()->GetConsoleSixAxis()->Activate(); + GetResourceManager()->GetSevenSixAxis()->Activate(); - GetResourceManager() - ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor) - .SetTransferMemoryAddress(t_mem_1->GetSourceAddress()); + GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress()); LOG_WARNING(Service_HID, "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, " @@ -1943,9 +1898,7 @@ void IHidServer::ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - GetResourceManager() - ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor) - .ResetTimestamp(); + GetResourceManager()->GetSevenSixAxis()->ResetTimestamp(); LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); @@ -1977,9 +1930,9 @@ void IHidServer::GetPalmaConnectionHandle(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); - Controller_Palma::PalmaConnectionHandle handle; - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); - const auto result = controller.GetPalmaConnectionHandle(parameters.npad_id, handle); + Palma::PalmaConnectionHandle handle; + auto controller = GetResourceManager()->GetPalma(); + const auto result = controller->GetPalmaConnectionHandle(parameters.npad_id, handle); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(result); @@ -1988,12 +1941,12 @@ void IHidServer::GetPalmaConnectionHandle(HLERequestContext& ctx) { void IHidServer::InitializePalma(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); - const auto result = controller.InitializePalma(connection_handle); + auto controller = GetResourceManager()->GetPalma(); + const auto result = controller->InitializePalma(connection_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -2001,27 +1954,27 @@ void IHidServer::InitializePalma(HLERequestContext& ctx) { void IHidServer::AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); + auto controller = GetResourceManager()->GetPalma(); IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(controller.AcquirePalmaOperationCompleteEvent(connection_handle)); + rb.PushCopyObjects(controller->AcquirePalmaOperationCompleteEvent(connection_handle)); } void IHidServer::GetPalmaOperationInfo(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - Controller_Palma::PalmaOperationType operation_type; - Controller_Palma::PalmaOperationData data; - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); - const auto result = controller.GetPalmaOperationInfo(connection_handle, operation_type, data); + Palma::PalmaOperationType operation_type; + Palma::PalmaOperationData data; + auto controller = GetResourceManager()->GetPalma(); + const auto result = controller->GetPalmaOperationInfo(connection_handle, operation_type, data); if (result.IsError()) { IPC::ResponseBuilder rb{ctx, 2}; @@ -2036,14 +1989,14 @@ void IHidServer::GetPalmaOperationInfo(HLERequestContext& ctx) { void IHidServer::PlayPalmaActivity(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; const auto palma_activity{rp.Pop<u64>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, palma_activity={}", connection_handle.npad_id, palma_activity); - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); - const auto result = controller.PlayPalmaActivity(connection_handle, palma_activity); + auto controller = GetResourceManager()->GetPalma(); + const auto result = controller->PlayPalmaActivity(connection_handle, palma_activity); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -2051,14 +2004,14 @@ void IHidServer::PlayPalmaActivity(HLERequestContext& ctx) { void IHidServer::SetPalmaFrModeType(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; - const auto fr_mode{rp.PopEnum<Controller_Palma::PalmaFrModeType>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; + const auto fr_mode{rp.PopEnum<Palma::PalmaFrModeType>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, fr_mode={}", connection_handle.npad_id, fr_mode); - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); - const auto result = controller.SetPalmaFrModeType(connection_handle, fr_mode); + auto controller = GetResourceManager()->GetPalma(); + const auto result = controller->SetPalmaFrModeType(connection_handle, fr_mode); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -2066,12 +2019,12 @@ void IHidServer::SetPalmaFrModeType(HLERequestContext& ctx) { void IHidServer::ReadPalmaStep(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); - const auto result = controller.ReadPalmaStep(connection_handle); + auto controller = GetResourceManager()->GetPalma(); + const auto result = controller->ReadPalmaStep(connection_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -2082,7 +2035,7 @@ void IHidServer::EnablePalmaStep(HLERequestContext& ctx) { struct Parameters { bool is_enabled; INSERT_PADDING_WORDS_NOINIT(1); - Controller_Palma::PalmaConnectionHandle connection_handle; + Palma::PalmaConnectionHandle connection_handle; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); @@ -2091,9 +2044,9 @@ void IHidServer::EnablePalmaStep(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, is_enabled={}", parameters.connection_handle.npad_id, parameters.is_enabled); - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); + auto controller = GetResourceManager()->GetPalma(); const auto result = - controller.EnablePalmaStep(parameters.connection_handle, parameters.is_enabled); + controller->EnablePalmaStep(parameters.connection_handle, parameters.is_enabled); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -2101,12 +2054,12 @@ void IHidServer::EnablePalmaStep(HLERequestContext& ctx) { void IHidServer::ResetPalmaStep(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); - const auto result = controller.ResetPalmaStep(connection_handle); + auto controller = GetResourceManager()->GetPalma(); + const auto result = controller->ResetPalmaStep(connection_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -2128,13 +2081,11 @@ void IHidServer::WritePalmaApplicationSection(HLERequestContext& ctx) { void IHidServer::ReadPalmaUniqueCode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .ReadPalmaUniqueCode(connection_handle); + GetResourceManager()->GetPalma()->ReadPalmaUniqueCode(connection_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2142,13 +2093,11 @@ void IHidServer::ReadPalmaUniqueCode(HLERequestContext& ctx) { void IHidServer::SetPalmaUniqueCodeInvalid(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .SetPalmaUniqueCodeInvalid(connection_handle); + GetResourceManager()->GetPalma()->SetPalmaUniqueCodeInvalid(connection_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2163,7 +2112,7 @@ void IHidServer::WritePalmaActivityEntry(HLERequestContext& ctx) { void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; const auto unknown{rp.Pop<u64>()}; [[maybe_unused]] const auto buffer = ctx.ReadBuffer(); @@ -2171,9 +2120,7 @@ void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}", connection_handle.npad_id, unknown); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .WritePalmaRgbLedPatternEntry(connection_handle, unknown); + GetResourceManager()->GetPalma()->WritePalmaRgbLedPatternEntry(connection_handle, unknown); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2181,8 +2128,8 @@ void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) { void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; - const auto wave_set{rp.PopEnum<Controller_Palma::PalmaWaveSet>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; + const auto wave_set{rp.PopEnum<Palma::PalmaWaveSet>()}; const auto unknown{rp.Pop<u64>()}; const auto t_mem_size{rp.Pop<u64>()}; const auto t_mem_handle{ctx.GetCopyHandle(0)}; @@ -2207,9 +2154,8 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) { "t_mem_handle=0x{:08X}, t_mem_size={}, size={}", connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .WritePalmaWaveEntry(connection_handle, wave_set, t_mem->GetSourceAddress(), t_mem_size); + GetResourceManager()->GetPalma()->WritePalmaWaveEntry(connection_handle, wave_set, + t_mem->GetSourceAddress(), t_mem_size); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2220,7 +2166,7 @@ void IHidServer::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) { struct Parameters { s32 database_id_version; INSERT_PADDING_WORDS_NOINIT(1); - Controller_Palma::PalmaConnectionHandle connection_handle; + Palma::PalmaConnectionHandle connection_handle; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); @@ -2229,10 +2175,8 @@ void IHidServer::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, database_id_version={}", parameters.connection_handle.npad_id, parameters.database_id_version); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .SetPalmaDataBaseIdentificationVersion(parameters.connection_handle, - parameters.database_id_version); + GetResourceManager()->GetPalma()->SetPalmaDataBaseIdentificationVersion( + parameters.connection_handle, parameters.database_id_version); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2240,13 +2184,11 @@ void IHidServer::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) { void IHidServer::GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .GetPalmaDataBaseIdentificationVersion(connection_handle); + GetResourceManager()->GetPalma()->GetPalmaDataBaseIdentificationVersion(connection_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2261,13 +2203,12 @@ void IHidServer::SuspendPalmaFeature(HLERequestContext& ctx) { void IHidServer::GetPalmaOperationResult(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - const auto result = GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .GetPalmaOperationResult(connection_handle); + const auto result = + GetResourceManager()->GetPalma()->GetPalmaOperationResult(connection_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -2302,9 +2243,7 @@ void IHidServer::SetIsPalmaAllConnectable(HLERequestContext& ctx) { "(STUBBED) called, is_palma_all_connectable={},applet_resource_user_id={}", parameters.is_palma_all_connectable, parameters.applet_resource_user_id); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .SetIsPalmaAllConnectable(parameters.is_palma_all_connectable); + GetResourceManager()->GetPalma()->SetIsPalmaAllConnectable(parameters.is_palma_all_connectable); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2319,13 +2258,11 @@ void IHidServer::SetIsPalmaPairedConnectable(HLERequestContext& ctx) { void IHidServer::PairPalma(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; + const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()}; LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .PairPalma(connection_handle); + GetResourceManager()->GetPalma()->PairPalma(connection_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2337,9 +2274,7 @@ void IHidServer::SetPalmaBoostMode(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode); - GetResourceManager() - ->GetController<Controller_Palma>(HidController::Palma) - .SetPalmaBoostMode(palma_boost_mode); + GetResourceManager()->GetPalma()->SetPalmaBoostMode(palma_boost_mode); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -2376,11 +2311,9 @@ void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) { void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()}; + const auto communication_mode{rp.PopEnum<NPad::NpadCommunicationMode>()}; - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .SetNpadCommunicationMode(communication_mode); + GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode); LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}", applet_resource_user_id, communication_mode); @@ -2396,9 +2329,7 @@ void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushEnum(GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetNpadCommunicationMode()); + rb.PushEnum(GetResourceManager()->GetNpad()->GetNpadCommunicationMode()); } void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) { diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp index 6f1902ee5..b56d0347a 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp @@ -16,206 +16,206 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour resource_manager{resource} { // clang-format off static const FunctionInfo functions[] = { - {31, nullptr, "SendKeyboardLockKeyEvent"}, - {101, nullptr, "AcquireHomeButtonEventHandle"}, - {111, nullptr, "ActivateHomeButton"}, - {121, nullptr, "AcquireSleepButtonEventHandle"}, - {131, nullptr, "ActivateSleepButton"}, - {141, nullptr, "AcquireCaptureButtonEventHandle"}, - {151, nullptr, "ActivateCaptureButton"}, - {161, nullptr, "GetPlatformConfig"}, - {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"}, - {211, nullptr, "GetNpadsWithNfc"}, - {212, nullptr, "AcquireNfcActivateEventHandle"}, - {213, nullptr, "ActivateNfc"}, - {214, nullptr, "GetXcdHandleForNpadWithNfc"}, - {215, nullptr, "IsNfcActivated"}, - {230, nullptr, "AcquireIrSensorEventHandle"}, - {231, nullptr, "ActivateIrSensor"}, - {232, nullptr, "GetIrSensorState"}, - {233, nullptr, "GetXcdHandleForNpadWithIrSensor"}, - {301, nullptr, "ActivateNpadSystem"}, - {303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"}, - {304, &IHidSystemServer::EnableAssigningSingleOnSlSrPress, "EnableAssigningSingleOnSlSrPress"}, - {305, &IHidSystemServer::DisableAssigningSingleOnSlSrPress, "DisableAssigningSingleOnSlSrPress"}, - {306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"}, - {307, nullptr, "GetNpadSystemExtStyle"}, - {308, &IHidSystemServer::ApplyNpadSystemCommonPolicyFull, "ApplyNpadSystemCommonPolicyFull"}, - {309, &IHidSystemServer::GetNpadFullKeyGripColor, "GetNpadFullKeyGripColor"}, - {310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"}, - {311, nullptr, "SetNpadPlayerLedBlinkingDevice"}, - {312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"}, - {313, nullptr, "GetNpadCaptureButtonAssignment"}, - {314, nullptr, "GetAppletFooterUiType"}, - {315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"}, - {316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"}, - {317, &IHidSystemServer::GetNpadLeftRightInterfaceType, "GetNpadLeftRightInterfaceType"}, - {318, &IHidSystemServer::HasBattery, "HasBattery"}, - {319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"}, - {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, - {322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"}, - {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, - {324, nullptr, "GetUniquePadButtonSet"}, - {325, nullptr, "GetUniquePadColor"}, - {326, nullptr, "GetUniquePadAppletDetailedUiType"}, - {327, nullptr, "GetAbstractedPadIdDataFromNpad"}, - {328, nullptr, "AttachAbstractedPadToNpad"}, - {329, nullptr, "DetachAbstractedPadAll"}, - {330, nullptr, "CheckAbstractedPadConnection"}, - {500, nullptr, "SetAppletResourceUserId"}, - {501, nullptr, "RegisterAppletResourceUserId"}, - {502, nullptr, "UnregisterAppletResourceUserId"}, - {503, nullptr, "EnableAppletToGetInput"}, - {504, nullptr, "SetAruidValidForVibration"}, - {505, nullptr, "EnableAppletToGetSixAxisSensor"}, - {506, nullptr, "EnableAppletToGetPadInput"}, - {507, nullptr, "EnableAppletToGetTouchScreen"}, - {510, nullptr, "SetVibrationMasterVolume"}, - {511, nullptr, "GetVibrationMasterVolume"}, - {512, nullptr, "BeginPermitVibrationSession"}, - {513, nullptr, "EndPermitVibrationSession"}, - {514, nullptr, "Unknown514"}, - {520, nullptr, "EnableHandheldHids"}, - {521, nullptr, "DisableHandheldHids"}, - {522, nullptr, "SetJoyConRailEnabled"}, - {523, nullptr, "IsJoyConRailEnabled"}, - {524, nullptr, "IsHandheldHidsEnabled"}, - {525, nullptr, "IsJoyConAttachedOnAllRail"}, - {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, - {541, nullptr, "GetPlayReportControllerUsages"}, - {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, - {543, nullptr, "GetRegisteredDevicesOld"}, - {544, &IHidSystemServer::AcquireConnectionTriggerTimeoutEvent, "AcquireConnectionTriggerTimeoutEvent"}, - {545, nullptr, "SendConnectionTrigger"}, - {546, &IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport, "AcquireDeviceRegisteredEventForControllerSupport"}, - {547, nullptr, "GetAllowedBluetoothLinksCount"}, - {548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"}, - {549, nullptr, "GetConnectableRegisteredDevices"}, - {700, nullptr, "ActivateUniquePad"}, - {702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"}, - {703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"}, - {751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"}, - {800, nullptr, "ListSixAxisSensorHandles"}, - {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"}, - {802, nullptr, "ResetSixAxisSensorCalibrationValues"}, - {803, nullptr, "StartSixAxisSensorUserCalibration"}, - {804, nullptr, "CancelSixAxisSensorUserCalibration"}, - {805, nullptr, "GetUniquePadBluetoothAddress"}, - {806, nullptr, "DisconnectUniquePad"}, - {807, nullptr, "GetUniquePadType"}, - {808, nullptr, "GetUniquePadInterface"}, - {809, nullptr, "GetUniquePadSerialNumber"}, - {810, nullptr, "GetUniquePadControllerNumber"}, - {811, nullptr, "GetSixAxisSensorUserCalibrationStage"}, - {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"}, - {821, nullptr, "StartAnalogStickManualCalibration"}, - {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"}, - {823, nullptr, "CancelAnalogStickManualCalibration"}, - {824, nullptr, "ResetAnalogStickManualCalibration"}, - {825, nullptr, "GetAnalogStickState"}, - {826, nullptr, "GetAnalogStickManualCalibrationStage"}, - {827, nullptr, "IsAnalogStickButtonPressed"}, - {828, nullptr, "IsAnalogStickInReleasePosition"}, - {829, nullptr, "IsAnalogStickInCircumference"}, - {830, nullptr, "SetNotificationLedPattern"}, - {831, nullptr, "SetNotificationLedPatternWithTimeout"}, - {832, nullptr, "PrepareHidsForNotificationWake"}, - {850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"}, - {851, nullptr, "EnableUsbFullKeyController"}, - {852, nullptr, "IsUsbConnected"}, - {870, &IHidSystemServer::IsHandheldButtonPressedOnConsoleMode, "IsHandheldButtonPressedOnConsoleMode"}, - {900, nullptr, "ActivateInputDetector"}, - {901, nullptr, "NotifyInputDetector"}, - {1000, &IHidSystemServer::InitializeFirmwareUpdate, "InitializeFirmwareUpdate"}, - {1001, nullptr, "GetFirmwareVersion"}, - {1002, nullptr, "GetAvailableFirmwareVersion"}, - {1003, nullptr, "IsFirmwareUpdateAvailable"}, - {1004, nullptr, "CheckFirmwareUpdateRequired"}, - {1005, nullptr, "StartFirmwareUpdate"}, - {1006, nullptr, "AbortFirmwareUpdate"}, - {1007, nullptr, "GetFirmwareUpdateState"}, - {1008, nullptr, "ActivateAudioControl"}, - {1009, nullptr, "AcquireAudioControlEventHandle"}, - {1010, nullptr, "GetAudioControlStates"}, - {1011, nullptr, "DeactivateAudioControl"}, - {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"}, - {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"}, - {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"}, - {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"}, - {1100, nullptr, "GetHidbusSystemServiceObject"}, - {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"}, - {1130, nullptr, "InitializeUsbFirmwareUpdate"}, - {1131, nullptr, "FinalizeUsbFirmwareUpdate"}, - {1132, nullptr, "CheckUsbFirmwareUpdateRequired"}, - {1133, nullptr, "StartUsbFirmwareUpdate"}, - {1134, nullptr, "GetUsbFirmwareUpdateState"}, - {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"}, - {1150, nullptr, "SetTouchScreenMagnification"}, - {1151, nullptr, "GetTouchScreenFirmwareVersion"}, - {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, - {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, - {1154, nullptr, "IsFirmwareAvailableForNotification"}, - {1155, nullptr, "SetForceHandheldStyleVibration"}, - {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, - {1157, nullptr, "CancelConnectionTrigger"}, - {1200, nullptr, "IsButtonConfigSupported"}, - {1201, nullptr, "IsButtonConfigEmbeddedSupported"}, - {1202, nullptr, "DeleteButtonConfig"}, - {1203, nullptr, "DeleteButtonConfigEmbedded"}, - {1204, nullptr, "SetButtonConfigEnabled"}, - {1205, nullptr, "SetButtonConfigEmbeddedEnabled"}, - {1206, nullptr, "IsButtonConfigEnabled"}, - {1207, nullptr, "IsButtonConfigEmbeddedEnabled"}, - {1208, nullptr, "SetButtonConfigEmbedded"}, - {1209, nullptr, "SetButtonConfigFull"}, - {1210, nullptr, "SetButtonConfigLeft"}, - {1211, nullptr, "SetButtonConfigRight"}, - {1212, nullptr, "GetButtonConfigEmbedded"}, - {1213, nullptr, "GetButtonConfigFull"}, - {1214, nullptr, "GetButtonConfigLeft"}, - {1215, nullptr, "GetButtonConfigRight"}, - {1250, nullptr, "IsCustomButtonConfigSupported"}, - {1251, nullptr, "IsDefaultButtonConfigEmbedded"}, - {1252, nullptr, "IsDefaultButtonConfigFull"}, - {1253, nullptr, "IsDefaultButtonConfigLeft"}, - {1254, nullptr, "IsDefaultButtonConfigRight"}, - {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"}, - {1256, nullptr, "IsButtonConfigStorageFullEmpty"}, - {1257, nullptr, "IsButtonConfigStorageLeftEmpty"}, - {1258, nullptr, "IsButtonConfigStorageRightEmpty"}, - {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"}, - {1260, nullptr, "GetButtonConfigStorageFullDeprecated"}, - {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"}, - {1262, nullptr, "GetButtonConfigStorageRightDeprecated"}, - {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"}, - {1264, nullptr, "SetButtonConfigStorageFullDeprecated"}, - {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"}, - {1266, nullptr, "SetButtonConfigStorageRightDeprecated"}, - {1267, nullptr, "DeleteButtonConfigStorageEmbedded"}, - {1268, nullptr, "DeleteButtonConfigStorageFull"}, - {1269, nullptr, "DeleteButtonConfigStorageLeft"}, - {1270, nullptr, "DeleteButtonConfigStorageRight"}, - {1271, nullptr, "IsUsingCustomButtonConfig"}, - {1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, - {1273, nullptr, "SetAllCustomButtonConfigEnabled"}, - {1274, nullptr, "SetDefaultButtonConfig"}, - {1275, nullptr, "SetAllDefaultButtonConfig"}, - {1276, nullptr, "SetHidButtonConfigEmbedded"}, - {1277, nullptr, "SetHidButtonConfigFull"}, - {1278, nullptr, "SetHidButtonConfigLeft"}, - {1279, nullptr, "SetHidButtonConfigRight"}, - {1280, nullptr, "GetHidButtonConfigEmbedded"}, - {1281, nullptr, "GetHidButtonConfigFull"}, - {1282, nullptr, "GetHidButtonConfigLeft"}, - {1283, nullptr, "GetHidButtonConfigRight"}, - {1284, nullptr, "GetButtonConfigStorageEmbedded"}, - {1285, nullptr, "GetButtonConfigStorageFull"}, - {1286, nullptr, "GetButtonConfigStorageLeft"}, - {1287, nullptr, "GetButtonConfigStorageRight"}, - {1288, nullptr, "SetButtonConfigStorageEmbedded"}, - {1289, nullptr, "SetButtonConfigStorageFull"}, - {1290, nullptr, "DeleteButtonConfigStorageRight"}, - {1291, nullptr, "DeleteButtonConfigStorageRight"}, + {31, nullptr, "SendKeyboardLockKeyEvent"}, + {101, nullptr, "AcquireHomeButtonEventHandle"}, + {111, nullptr, "ActivateHomeButton"}, + {121, nullptr, "AcquireSleepButtonEventHandle"}, + {131, nullptr, "ActivateSleepButton"}, + {141, nullptr, "AcquireCaptureButtonEventHandle"}, + {151, nullptr, "ActivateCaptureButton"}, + {161, nullptr, "GetPlatformConfig"}, + {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"}, + {211, nullptr, "GetNpadsWithNfc"}, + {212, nullptr, "AcquireNfcActivateEventHandle"}, + {213, nullptr, "ActivateNfc"}, + {214, nullptr, "GetXcdHandleForNpadWithNfc"}, + {215, nullptr, "IsNfcActivated"}, + {230, nullptr, "AcquireIrSensorEventHandle"}, + {231, nullptr, "ActivateIrSensor"}, + {232, nullptr, "GetIrSensorState"}, + {233, nullptr, "GetXcdHandleForNpadWithIrSensor"}, + {301, nullptr, "ActivateNpadSystem"}, + {303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"}, + {304, &IHidSystemServer::EnableAssigningSingleOnSlSrPress, "EnableAssigningSingleOnSlSrPress"}, + {305, &IHidSystemServer::DisableAssigningSingleOnSlSrPress, "DisableAssigningSingleOnSlSrPress"}, + {306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"}, + {307, nullptr, "GetNpadSystemExtStyle"}, + {308, &IHidSystemServer::ApplyNpadSystemCommonPolicyFull, "ApplyNpadSystemCommonPolicyFull"}, + {309, &IHidSystemServer::GetNpadFullKeyGripColor, "GetNpadFullKeyGripColor"}, + {310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"}, + {311, nullptr, "SetNpadPlayerLedBlinkingDevice"}, + {312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"}, + {313, nullptr, "GetNpadCaptureButtonAssignment"}, + {314, nullptr, "GetAppletFooterUiType"}, + {315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"}, + {316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"}, + {317, &IHidSystemServer::GetNpadLeftRightInterfaceType, "GetNpadLeftRightInterfaceType"}, + {318, &IHidSystemServer::HasBattery, "HasBattery"}, + {319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"}, + {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, + {322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"}, + {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, + {324, nullptr, "GetUniquePadButtonSet"}, + {325, nullptr, "GetUniquePadColor"}, + {326, nullptr, "GetUniquePadAppletDetailedUiType"}, + {327, nullptr, "GetAbstractedPadIdDataFromNpad"}, + {328, nullptr, "AttachAbstractedPadToNpad"}, + {329, nullptr, "DetachAbstractedPadAll"}, + {330, nullptr, "CheckAbstractedPadConnection"}, + {500, nullptr, "SetAppletResourceUserId"}, + {501, nullptr, "RegisterAppletResourceUserId"}, + {502, nullptr, "UnregisterAppletResourceUserId"}, + {503, nullptr, "EnableAppletToGetInput"}, + {504, nullptr, "SetAruidValidForVibration"}, + {505, nullptr, "EnableAppletToGetSixAxisSensor"}, + {506, nullptr, "EnableAppletToGetPadInput"}, + {507, nullptr, "EnableAppletToGetTouchScreen"}, + {510, nullptr, "SetVibrationMasterVolume"}, + {511, nullptr, "GetVibrationMasterVolume"}, + {512, nullptr, "BeginPermitVibrationSession"}, + {513, nullptr, "EndPermitVibrationSession"}, + {514, nullptr, "Unknown514"}, + {520, nullptr, "EnableHandheldHids"}, + {521, nullptr, "DisableHandheldHids"}, + {522, nullptr, "SetJoyConRailEnabled"}, + {523, nullptr, "IsJoyConRailEnabled"}, + {524, nullptr, "IsHandheldHidsEnabled"}, + {525, nullptr, "IsJoyConAttachedOnAllRail"}, + {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, + {541, nullptr, "GetPlayReportControllerUsages"}, + {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, + {543, nullptr, "GetRegisteredDevicesOld"}, + {544, &IHidSystemServer::AcquireConnectionTriggerTimeoutEvent, "AcquireConnectionTriggerTimeoutEvent"}, + {545, nullptr, "SendConnectionTrigger"}, + {546, &IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport, "AcquireDeviceRegisteredEventForControllerSupport"}, + {547, nullptr, "GetAllowedBluetoothLinksCount"}, + {548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"}, + {549, nullptr, "GetConnectableRegisteredDevices"}, + {700, nullptr, "ActivateUniquePad"}, + {702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"}, + {703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"}, + {751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"}, + {800, nullptr, "ListSixAxisSensorHandles"}, + {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"}, + {802, nullptr, "ResetSixAxisSensorCalibrationValues"}, + {803, nullptr, "StartSixAxisSensorUserCalibration"}, + {804, nullptr, "CancelSixAxisSensorUserCalibration"}, + {805, nullptr, "GetUniquePadBluetoothAddress"}, + {806, nullptr, "DisconnectUniquePad"}, + {807, nullptr, "GetUniquePadType"}, + {808, nullptr, "GetUniquePadInterface"}, + {809, nullptr, "GetUniquePadSerialNumber"}, + {810, nullptr, "GetUniquePadControllerNumber"}, + {811, nullptr, "GetSixAxisSensorUserCalibrationStage"}, + {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"}, + {821, nullptr, "StartAnalogStickManualCalibration"}, + {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"}, + {823, nullptr, "CancelAnalogStickManualCalibration"}, + {824, nullptr, "ResetAnalogStickManualCalibration"}, + {825, nullptr, "GetAnalogStickState"}, + {826, nullptr, "GetAnalogStickManualCalibrationStage"}, + {827, nullptr, "IsAnalogStickButtonPressed"}, + {828, nullptr, "IsAnalogStickInReleasePosition"}, + {829, nullptr, "IsAnalogStickInCircumference"}, + {830, nullptr, "SetNotificationLedPattern"}, + {831, nullptr, "SetNotificationLedPatternWithTimeout"}, + {832, nullptr, "PrepareHidsForNotificationWake"}, + {850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"}, + {851, nullptr, "EnableUsbFullKeyController"}, + {852, nullptr, "IsUsbConnected"}, + {870, &IHidSystemServer::IsHandheldButtonPressedOnConsoleMode, "IsHandheldButtonPressedOnConsoleMode"}, + {900, nullptr, "ActivateInputDetector"}, + {901, nullptr, "NotifyInputDetector"}, + {1000, &IHidSystemServer::InitializeFirmwareUpdate, "InitializeFirmwareUpdate"}, + {1001, nullptr, "GetFirmwareVersion"}, + {1002, nullptr, "GetAvailableFirmwareVersion"}, + {1003, nullptr, "IsFirmwareUpdateAvailable"}, + {1004, nullptr, "CheckFirmwareUpdateRequired"}, + {1005, nullptr, "StartFirmwareUpdate"}, + {1006, nullptr, "AbortFirmwareUpdate"}, + {1007, nullptr, "GetFirmwareUpdateState"}, + {1008, nullptr, "ActivateAudioControl"}, + {1009, nullptr, "AcquireAudioControlEventHandle"}, + {1010, nullptr, "GetAudioControlStates"}, + {1011, nullptr, "DeactivateAudioControl"}, + {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"}, + {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"}, + {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"}, + {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"}, + {1100, nullptr, "GetHidbusSystemServiceObject"}, + {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"}, + {1130, nullptr, "InitializeUsbFirmwareUpdate"}, + {1131, nullptr, "FinalizeUsbFirmwareUpdate"}, + {1132, nullptr, "CheckUsbFirmwareUpdateRequired"}, + {1133, nullptr, "StartUsbFirmwareUpdate"}, + {1134, nullptr, "GetUsbFirmwareUpdateState"}, + {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"}, + {1150, nullptr, "SetTouchScreenMagnification"}, + {1151, nullptr, "GetTouchScreenFirmwareVersion"}, + {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, + {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, + {1154, nullptr, "IsFirmwareAvailableForNotification"}, + {1155, nullptr, "SetForceHandheldStyleVibration"}, + {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, + {1157, nullptr, "CancelConnectionTrigger"}, + {1200, nullptr, "IsButtonConfigSupported"}, + {1201, nullptr, "IsButtonConfigEmbeddedSupported"}, + {1202, nullptr, "DeleteButtonConfig"}, + {1203, nullptr, "DeleteButtonConfigEmbedded"}, + {1204, nullptr, "SetButtonConfigEnabled"}, + {1205, nullptr, "SetButtonConfigEmbeddedEnabled"}, + {1206, nullptr, "IsButtonConfigEnabled"}, + {1207, nullptr, "IsButtonConfigEmbeddedEnabled"}, + {1208, nullptr, "SetButtonConfigEmbedded"}, + {1209, nullptr, "SetButtonConfigFull"}, + {1210, nullptr, "SetButtonConfigLeft"}, + {1211, nullptr, "SetButtonConfigRight"}, + {1212, nullptr, "GetButtonConfigEmbedded"}, + {1213, nullptr, "GetButtonConfigFull"}, + {1214, nullptr, "GetButtonConfigLeft"}, + {1215, nullptr, "GetButtonConfigRight"}, + {1250, nullptr, "IsCustomButtonConfigSupported"}, + {1251, nullptr, "IsDefaultButtonConfigEmbedded"}, + {1252, nullptr, "IsDefaultButtonConfigFull"}, + {1253, nullptr, "IsDefaultButtonConfigLeft"}, + {1254, nullptr, "IsDefaultButtonConfigRight"}, + {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"}, + {1256, nullptr, "IsButtonConfigStorageFullEmpty"}, + {1257, nullptr, "IsButtonConfigStorageLeftEmpty"}, + {1258, nullptr, "IsButtonConfigStorageRightEmpty"}, + {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"}, + {1260, nullptr, "GetButtonConfigStorageFullDeprecated"}, + {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"}, + {1262, nullptr, "GetButtonConfigStorageRightDeprecated"}, + {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"}, + {1264, nullptr, "SetButtonConfigStorageFullDeprecated"}, + {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"}, + {1266, nullptr, "SetButtonConfigStorageRightDeprecated"}, + {1267, nullptr, "DeleteButtonConfigStorageEmbedded"}, + {1268, nullptr, "DeleteButtonConfigStorageFull"}, + {1269, nullptr, "DeleteButtonConfigStorageLeft"}, + {1270, nullptr, "DeleteButtonConfigStorageRight"}, + {1271, nullptr, "IsUsingCustomButtonConfig"}, + {1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, + {1273, nullptr, "SetAllCustomButtonConfigEnabled"}, + {1274, nullptr, "SetDefaultButtonConfig"}, + {1275, nullptr, "SetAllDefaultButtonConfig"}, + {1276, nullptr, "SetHidButtonConfigEmbedded"}, + {1277, nullptr, "SetHidButtonConfigFull"}, + {1278, nullptr, "SetHidButtonConfigLeft"}, + {1279, nullptr, "SetHidButtonConfigRight"}, + {1280, nullptr, "GetHidButtonConfigEmbedded"}, + {1281, nullptr, "GetHidButtonConfigFull"}, + {1282, nullptr, "GetHidButtonConfigLeft"}, + {1283, nullptr, "GetHidButtonConfigRight"}, + {1284, nullptr, "GetButtonConfigStorageEmbedded"}, + {1285, nullptr, "GetButtonConfigStorageFull"}, + {1286, nullptr, "GetButtonConfigStorageLeft"}, + {1287, nullptr, "GetButtonConfigStorageRight"}, + {1288, nullptr, "SetButtonConfigStorageEmbedded"}, + {1289, nullptr, "SetButtonConfigStorageFull"}, + {1290, nullptr, "DeleteButtonConfigStorageRight"}, + {1291, nullptr, "DeleteButtonConfigStorageRight"}, }; // clang-format on @@ -240,9 +240,7 @@ IHidSystemServer::~IHidSystemServer() { void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "called"); - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .ApplyNpadSystemCommonPolicy(); + GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -273,9 +271,7 @@ void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) { void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "called"); - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .ApplyNpadSystemCommonPolicy(); + GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -304,10 +300,7 @@ void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) { LOG_INFO(Service_HID, "(STUBBED) called"); Core::HID::NpadStyleSet supported_styleset = - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetSupportedStyleSet() - .raw; + GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw; IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -320,10 +313,7 @@ void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) { LOG_INFO(Service_HID, "(STUBBED) called"); Core::HID::NpadStyleSet supported_styleset = - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetSupportedStyleSet() - .raw; + GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw; IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -337,10 +327,8 @@ void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, npad_id_type={}", npad_id_type); // Spams a lot when controller applet is running - const Service::HID::Controller_NPad::AppletDetailedUiType detailed_ui_type = - GetResourceManager() - ->GetController<Controller_NPad>(HidController::NPad) - .GetAppletDetailedUiType(npad_id_type); + const NPad::AppletDetailedUiType detailed_ui_type = + GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/hid/hid_util.h b/src/core/hle/service/hid/hid_util.h new file mode 100644 index 000000000..b87cc10e3 --- /dev/null +++ b/src/core/hle/service/hid/hid_util.h @@ -0,0 +1,146 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hid/hid_types.h" +#include "core/hle/service/hid/errors.h" + +namespace Service::HID { + +constexpr bool IsNpadIdValid(const Core::HID::NpadIdType npad_id) { + switch (npad_id) { + case Core::HID::NpadIdType::Player1: + case Core::HID::NpadIdType::Player2: + case Core::HID::NpadIdType::Player3: + case Core::HID::NpadIdType::Player4: + case Core::HID::NpadIdType::Player5: + case Core::HID::NpadIdType::Player6: + case Core::HID::NpadIdType::Player7: + case Core::HID::NpadIdType::Player8: + case Core::HID::NpadIdType::Other: + case Core::HID::NpadIdType::Handheld: + return true; + default: + return false; + } +} + +constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& handle) { + const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id)); + const bool device_index = handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; + + if (!npad_id) { + return InvalidNpadId; + } + if (!device_index) { + return NpadDeviceIndexOutOfRange; + } + + return ResultSuccess; +} + +constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) { + switch (handle.npad_type) { + case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Handheld: + case Core::HID::NpadStyleIndex::JoyconDual: + case Core::HID::NpadStyleIndex::JoyconLeft: + case Core::HID::NpadStyleIndex::JoyconRight: + case Core::HID::NpadStyleIndex::GameCube: + case Core::HID::NpadStyleIndex::N64: + case Core::HID::NpadStyleIndex::SystemExt: + case Core::HID::NpadStyleIndex::System: + // These support vibration + break; + default: + return VibrationInvalidStyleIndex; + } + + if (!IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id))) { + return VibrationInvalidNpadId; + } + + if (handle.device_index >= Core::HID::DeviceIndex::MaxDeviceIndex) { + return VibrationDeviceIndexOutOfRange; + } + + return ResultSuccess; +} + +/// Converts a Core::HID::NpadIdType to an array index. +constexpr size_t NpadIdTypeToIndex(Core::HID::NpadIdType npad_id_type) { + switch (npad_id_type) { + case Core::HID::NpadIdType::Player1: + return 0; + case Core::HID::NpadIdType::Player2: + return 1; + case Core::HID::NpadIdType::Player3: + return 2; + case Core::HID::NpadIdType::Player4: + return 3; + case Core::HID::NpadIdType::Player5: + return 4; + case Core::HID::NpadIdType::Player6: + return 5; + case Core::HID::NpadIdType::Player7: + return 6; + case Core::HID::NpadIdType::Player8: + return 7; + case Core::HID::NpadIdType::Handheld: + return 8; + case Core::HID::NpadIdType::Other: + return 9; + default: + return 8; + } +} + +/// Converts an array index to a Core::HID::NpadIdType +constexpr Core::HID::NpadIdType IndexToNpadIdType(size_t index) { + switch (index) { + case 0: + return Core::HID::NpadIdType::Player1; + case 1: + return Core::HID::NpadIdType::Player2; + case 2: + return Core::HID::NpadIdType::Player3; + case 3: + return Core::HID::NpadIdType::Player4; + case 4: + return Core::HID::NpadIdType::Player5; + case 5: + return Core::HID::NpadIdType::Player6; + case 6: + return Core::HID::NpadIdType::Player7; + case 7: + return Core::HID::NpadIdType::Player8; + case 8: + return Core::HID::NpadIdType::Handheld; + case 9: + return Core::HID::NpadIdType::Other; + default: + return Core::HID::NpadIdType::Invalid; + } +} + +constexpr Core::HID::NpadStyleSet GetStylesetByIndex(std::size_t index) { + switch (index) { + case 0: + return Core::HID::NpadStyleSet::Fullkey; + case 1: + return Core::HID::NpadStyleSet::Handheld; + case 2: + return Core::HID::NpadStyleSet::JoyDual; + case 3: + return Core::HID::NpadStyleSet::JoyLeft; + case 4: + return Core::HID::NpadStyleSet::JoyRight; + case 5: + return Core::HID::NpadStyleSet::Palma; + default: + return Core::HID::NpadStyleSet::None; + } +} + +} // namespace Service::HID diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index d383a266d..39b9a4474 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -12,6 +12,7 @@ #include "core/hle/kernel/k_transfer_memory.h" #include "core/hle/kernel/kernel.h" #include "core/hle/service/hid/errors.h" +#include "core/hle/service/hid/hid_util.h" #include "core/hle/service/hid/irs.h" #include "core/hle/service/hid/irsensor/clustering_processor.h" #include "core/hle/service/hid/irsensor/image_transfer_processor.h" @@ -320,7 +321,7 @@ void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) { } Core::IrSensor::IrCameraHandle camera_handle{ - .npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)), + .npad_id = static_cast<u8>(HID::NpadIdTypeToIndex(npad_id)), .npad_type = Core::HID::NpadStyleIndex::None, }; @@ -545,7 +546,7 @@ void IRS::ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx) { Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const { if (camera_handle.npad_id > - static_cast<u8>(NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) { + static_cast<u8>(HID::NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) { return InvalidIrCameraHandle; } if (camera_handle.npad_type != Core::HID::NpadStyleIndex::None) { diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp index d6f42c646..e76d4eea9 100644 --- a/src/core/hle/service/hid/resource_manager.cpp +++ b/src/core/hle/service/hid/resource_manager.cpp @@ -9,14 +9,15 @@ #include "core/hle/service/hid/resource_manager.h" #include "core/hle/service/ipc_helpers.h" -#include "core/hle/service/hid/controllers/console_sixaxis.h" -#include "core/hle/service/hid/controllers/controller_base.h" +#include "core/hle/service/hid/controllers/console_six_axis.h" #include "core/hle/service/hid/controllers/debug_pad.h" #include "core/hle/service/hid/controllers/gesture.h" #include "core/hle/service/hid/controllers/keyboard.h" #include "core/hle/service/hid/controllers/mouse.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/palma.h" +#include "core/hle/service/hid/controllers/seven_six_axis.h" +#include "core/hle/service/hid/controllers/six_axis.h" #include "core/hle/service/hid/controllers/stubbed.h" #include "core/hle/service/hid/controllers/touchscreen.h" #include "core/hle/service/hid/controllers/xpad.h" @@ -42,76 +43,132 @@ void ResourceManager::Initialize() { } u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer(); - MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory); - MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory); - MakeController<Controller_Mouse>(HidController::Mouse, shared_memory); - MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory); - MakeController<Controller_XPad>(HidController::XPad, shared_memory); - MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory); - MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory); - MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory); - MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory); - MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory); - MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory); - MakeController<Controller_Gesture>(HidController::Gesture, shared_memory); - MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory); - MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory); - MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory); + debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory); + mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory); + debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory); + keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory); + unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory); + npad = std::make_shared<NPad>(system.HIDCore(), shared_memory, service_context); + gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory); + touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory); + xpad = std::make_shared<XPad>(system.HIDCore(), shared_memory); + + palma = std::make_shared<Palma>(system.HIDCore(), shared_memory, service_context); + + home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory); + sleep_button = std::make_shared<SleepButton>(system.HIDCore(), shared_memory); + capture_button = std::make_shared<CaptureButton>(system.HIDCore(), shared_memory); + + six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad); + console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory); + seven_six_axis = std::make_shared<SevenSixAxis>(system); + + home_button->SetCommonHeaderOffset(0x4C00); + sleep_button->SetCommonHeaderOffset(0x4E00); + capture_button->SetCommonHeaderOffset(0x5000); + unique_pad->SetCommonHeaderOffset(0x5A00); + debug_mouse->SetCommonHeaderOffset(0x3DC00); // Homebrew doesn't try to activate some controllers, so we activate them by default - GetController<Controller_NPad>(HidController::NPad).Activate(); - GetController<Controller_Touchscreen>(HidController::Touchscreen).Activate(); - - GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00); - GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00); - GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000); - GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200); - GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); - GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00); + npad->Activate(); + six_axis->Activate(); + touch_screen->Activate(); system.HIDCore().ReloadInputDevices(); is_initialized = true; } +std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const { + return capture_button; +} + +std::shared_ptr<ConsoleSixAxis> ResourceManager::GetConsoleSixAxis() const { + return console_six_axis; +} + +std::shared_ptr<DebugMouse> ResourceManager::GetDebugMouse() const { + return debug_mouse; +} + +std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const { + return debug_pad; +} + +std::shared_ptr<Gesture> ResourceManager::GetGesture() const { + return gesture; +} + +std::shared_ptr<HomeButton> ResourceManager::GetHomeButton() const { + return home_button; +} + +std::shared_ptr<Keyboard> ResourceManager::GetKeyboard() const { + return keyboard; +} + +std::shared_ptr<Mouse> ResourceManager::GetMouse() const { + return mouse; +} + +std::shared_ptr<NPad> ResourceManager::GetNpad() const { + return npad; +} + +std::shared_ptr<Palma> ResourceManager::GetPalma() const { + return palma; +} + +std::shared_ptr<SevenSixAxis> ResourceManager::GetSevenSixAxis() const { + return seven_six_axis; +} + +std::shared_ptr<SixAxis> ResourceManager::GetSixAxis() const { + return six_axis; +} + +std::shared_ptr<SleepButton> ResourceManager::GetSleepButton() const { + return sleep_button; +} + +std::shared_ptr<TouchScreen> ResourceManager::GetTouchScreen() const { + return touch_screen; +} + +std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const { + return unique_pad; +} void ResourceManager::UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - - for (const auto& controller : controllers) { - // Keyboard has it's own update event - if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) { - continue; - } - // Mouse has it's own update event - if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { - continue; - } - // Npad has it's own update event - if (controller == controllers[static_cast<size_t>(HidController::NPad)]) { - continue; - } - controller->OnUpdate(core_timing); - } + debug_pad->OnUpdate(core_timing); + unique_pad->OnUpdate(core_timing); + gesture->OnUpdate(core_timing); + touch_screen->OnUpdate(core_timing); + palma->OnUpdate(core_timing); + home_button->OnUpdate(core_timing); + sleep_button->OnUpdate(core_timing); + capture_button->OnUpdate(core_timing); + xpad->OnUpdate(core_timing); } void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - - controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing); + npad->OnUpdate(core_timing); } void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - - controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); - controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); + mouse->OnUpdate(core_timing); + debug_mouse->OnUpdate(core_timing); + keyboard->OnUpdate(core_timing); } void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - - controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); + six_axis->OnUpdate(core_timing); + seven_six_axis->OnUpdate(core_timing); + console_six_axis->OnUpdate(core_timing); } IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource) diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h index 34dbf36bc..2b6a9b5e6 100644 --- a/src/core/hle/service/hid/resource_manager.h +++ b/src/core/hle/service/hid/resource_manager.h @@ -3,10 +3,6 @@ #pragma once -#include <chrono> - -#include "core/core.h" -#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/service.h" @@ -14,74 +10,85 @@ namespace Core::Timing { struct EventType; } -namespace Core::HID { -class HIDCore; -} - namespace Service::HID { +class Controller_Stubbed; +class ConsoleSixAxis; +class DebugPad; +class Gesture; +class Keyboard; +class Mouse; +class NPad; +class Palma; +class SevenSixAxis; +class SixAxis; +class TouchScreen; +class XPad; + +using CaptureButton = Controller_Stubbed; +using DebugMouse = Controller_Stubbed; +using HomeButton = Controller_Stubbed; +using SleepButton = Controller_Stubbed; +using UniquePad = Controller_Stubbed; -enum class HidController : std::size_t { - DebugPad, - Touchscreen, - Mouse, - Keyboard, - XPad, - HomeButton, - SleepButton, - CaptureButton, - InputDetector, - UniquePad, - NPad, - Gesture, - ConsoleSixAxisSensor, - DebugMouse, - Palma, - - MaxControllers, -}; class ResourceManager { + public: explicit ResourceManager(Core::System& system_); ~ResourceManager(); - template <typename T> - T& GetController(HidController controller) { - return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); - } - - template <typename T> - const T& GetController(HidController controller) const { - return static_cast<T&>(*controllers[static_cast<size_t>(controller)]); - } - void Initialize(); + std::shared_ptr<CaptureButton> GetCaptureButton() const; + std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const; + std::shared_ptr<DebugMouse> GetDebugMouse() const; + std::shared_ptr<DebugPad> GetDebugPad() const; + std::shared_ptr<Gesture> GetGesture() const; + std::shared_ptr<HomeButton> GetHomeButton() const; + std::shared_ptr<Keyboard> GetKeyboard() const; + std::shared_ptr<Mouse> GetMouse() const; + std::shared_ptr<NPad> GetNpad() const; + std::shared_ptr<Palma> GetPalma() const; + std::shared_ptr<SevenSixAxis> GetSevenSixAxis() const; + std::shared_ptr<SixAxis> GetSixAxis() const; + std::shared_ptr<SleepButton> GetSleepButton() const; + std::shared_ptr<TouchScreen> GetTouchScreen() const; + std::shared_ptr<UniquePad> GetUniquePad() const; + void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); private: - template <typename T> - void MakeController(HidController controller, u8* shared_memory) { - if constexpr (std::is_constructible_v<T, Core::System&, u8*>) { - controllers[static_cast<std::size_t>(controller)] = - std::make_unique<T>(system, shared_memory); - } else { - controllers[static_cast<std::size_t>(controller)] = - std::make_unique<T>(system.HIDCore(), shared_memory); - } - } - - template <typename T> - void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) { - controllers[static_cast<std::size_t>(controller)] = - std::make_unique<T>(system.HIDCore(), shared_memory, service_context); - } - bool is_initialized{false}; - std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> - controllers{}; + + std::shared_ptr<CaptureButton> capture_button = nullptr; + std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr; + std::shared_ptr<DebugMouse> debug_mouse = nullptr; + std::shared_ptr<DebugPad> debug_pad = nullptr; + std::shared_ptr<Gesture> gesture = nullptr; + std::shared_ptr<HomeButton> home_button = nullptr; + std::shared_ptr<Keyboard> keyboard = nullptr; + std::shared_ptr<Mouse> mouse = nullptr; + std::shared_ptr<NPad> npad = nullptr; + std::shared_ptr<Palma> palma = nullptr; + std::shared_ptr<SevenSixAxis> seven_six_axis = nullptr; + std::shared_ptr<SixAxis> six_axis = nullptr; + std::shared_ptr<SleepButton> sleep_button = nullptr; + std::shared_ptr<TouchScreen> touch_screen = nullptr; + std::shared_ptr<UniquePad> unique_pad = nullptr; + std::shared_ptr<XPad> xpad = nullptr; + + // TODO: Create these resources + // std::shared_ptr<AudioControl> audio_control = nullptr; + // std::shared_ptr<ButtonConfig> button_config = nullptr; + // std::shared_ptr<Config> config = nullptr; + // std::shared_ptr<Connection> connection = nullptr; + // std::shared_ptr<CustomConfig> custom_config = nullptr; + // std::shared_ptr<Digitizer> digitizer = nullptr; + // std::shared_ptr<Hdls> hdls = nullptr; + // std::shared_ptr<PlayReport> play_report = nullptr; + // std::shared_ptr<Rail> rail = nullptr; Core::System& system; KernelHelpers::ServiceContext service_context; diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp index a71d26157..ad534177d 100644 --- a/src/core/hle/service/nfc/common/device_manager.cpp +++ b/src/core/hle/service/nfc/common/device_manager.cpp @@ -7,6 +7,7 @@ #include "core/core.h" #include "core/hid/hid_types.h" #include "core/hle/kernel/k_event.h" +#include "core/hle/service/hid/hid_util.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/nfc/common/device.h" #include "core/hle/service/nfc/common/device_manager.h" @@ -24,7 +25,7 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex for (u32 device_index = 0; device_index < devices.size(); device_index++) { devices[device_index] = - std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, + std::make_shared<NfcDevice>(HID::IndexToNpadIdType(device_index), system, service_context, availability_change_event); } diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index da140c01c..db30ba598 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -68,10 +68,7 @@ u64 StandardVmCallbacks::HidKeysDown() { return 0; } - const auto press_state = - applet_resource - ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad) - .GetAndResetPressState(); + const auto press_state = applet_resource->GetNpad()->GetAndResetPressState(); return static_cast<u64>(press_state & HID::NpadButton::All); } diff --git a/src/frontend_common/CMakeLists.txt b/src/frontend_common/CMakeLists.txt new file mode 100644 index 000000000..1537271fc --- /dev/null +++ b/src/frontend_common/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2023 yuzu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +add_library(frontend_common STATIC + config.cpp + config.h +) + +create_target_directory_groups(frontend_common) +target_link_libraries(frontend_common PUBLIC core SimpleIni PRIVATE common Boost::headers) diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp new file mode 100644 index 000000000..7474cb0f9 --- /dev/null +++ b/src/frontend_common/config.cpp @@ -0,0 +1,1008 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <algorithm> +#include <array> +#include "common/fs/fs.h" +#include "common/fs/path_util.h" +#include "common/settings.h" +#include "common/settings_common.h" +#include "common/settings_enums.h" +#include "config.h" +#include "core/core.h" +#include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/hid/controllers/npad.h" +#include "network/network.h" + +#include <boost/algorithm/string/replace.hpp> + +#include "common/string_util.h" + +namespace FS = Common::FS; + +Config::Config(const ConfigType config_type) + : type(config_type), global{config_type == ConfigType::GlobalConfig} {} + +void Config::Initialize(const std::string& config_name) { + const std::filesystem::path fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); + const auto config_file = fmt::format("{}.ini", config_name); + + switch (type) { + case ConfigType::GlobalConfig: + config_loc = FS::PathToUTF8String(fs_config_loc / config_file); + void(FS::CreateParentDir(config_loc)); + SetUpIni(); + Reload(); + break; + case ConfigType::PerGameConfig: + config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); + void(FS::CreateParentDir(config_loc)); + SetUpIni(); + Reload(); + break; + case ConfigType::InputProfile: + config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); + void(FS::CreateParentDir(config_loc)); + SetUpIni(); + break; + } +} + +void Config::Initialize(const std::optional<std::string> config_path) { + const std::filesystem::path default_sdl_config_path = + FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini"; + config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path)); + void(FS::CreateParentDir(config_loc)); + SetUpIni(); + Reload(); +} + +void Config::WriteToIni() const { + FILE* fp = nullptr; +#ifdef _WIN32 + fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb"); +#else + fp = fopen(config_loc.c_str(), "wb"); +#endif + + if (fp == nullptr) { + LOG_ERROR(Frontend, "Config file could not be saved!"); + return; + } + + CSimpleIniA::FileWriter writer(fp); + const SI_Error rc = config->Save(writer, false); + if (rc < 0) { + LOG_ERROR(Frontend, "Config file could not be saved!"); + } + fclose(fp); +} + +void Config::SetUpIni() { + config = std::make_unique<CSimpleIniA>(); + config->SetUnicode(true); + config->SetSpaces(false); + + FILE* fp = nullptr; +#ifdef _WIN32 + _wfopen_s(&fp, Common::UTF8ToUTF16W(config_loc).data(), L"rb, ccs=UTF-8"); + if (fp == nullptr) { + fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb, ccs=UTF-8"); + } +#else + fp = fopen(config_loc.c_str(), "rb"); + if (fp == nullptr) { + fp = fopen(config_loc.c_str(), "wb"); + } +#endif + + if (fp == nullptr) { + LOG_ERROR(Frontend, "Config file could not be loaded!"); + return; + } + + if (SI_Error rc = config->LoadFile(fp); rc < 0) { + LOG_ERROR(Frontend, "Config file could not be loaded!"); + } + fclose(fp); +} + +bool Config::IsCustomConfig() const { + return type == ConfigType::PerGameConfig; +} + +void Config::ReadPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix.append("player_").append(ToString(player_index)).append("_"); + } + + auto& player = Settings::values.players.GetValue()[player_index]; + if (IsCustomConfig()) { + const auto profile_name = + ReadStringSetting(std::string(player_prefix).append("profile_name")); + if (profile_name.empty()) { + // Use the global input config + player = Settings::values.players.GetValue(true)[player_index]; + return; + } + player.profile_name = profile_name; + } + + if (player_prefix.empty() && Settings::IsConfiguringGlobal()) { + const auto controller = static_cast<Settings::ControllerType>( + ReadIntegerSetting(std::string(player_prefix).append("type"), + static_cast<u8>(Settings::ControllerType::ProController))); + + if (controller == Settings::ControllerType::LeftJoycon || + controller == Settings::ControllerType::RightJoycon) { + player.controller_type = controller; + } + } else { + std::string connected_key = player_prefix; + player.connected = ReadBooleanSetting(connected_key.append("connected"), + std::make_optional(player_index == 0)); + + player.controller_type = static_cast<Settings::ControllerType>( + ReadIntegerSetting(std::string(player_prefix).append("type"), + static_cast<u8>(Settings::ControllerType::ProController))); + + player.vibration_enabled = ReadBooleanSetting( + std::string(player_prefix).append("vibration_enabled"), std::make_optional(true)); + + player.vibration_strength = static_cast<int>( + ReadIntegerSetting(std::string(player_prefix).append("vibration_strength"), 100)); + + player.body_color_left = static_cast<u32>(ReadIntegerSetting( + std::string(player_prefix).append("body_color_left"), Settings::JOYCON_BODY_NEON_BLUE)); + player.body_color_right = static_cast<u32>(ReadIntegerSetting( + std::string(player_prefix).append("body_color_right"), Settings::JOYCON_BODY_NEON_RED)); + player.button_color_left = static_cast<u32>( + ReadIntegerSetting(std::string(player_prefix).append("button_color_left"), + Settings::JOYCON_BUTTONS_NEON_BLUE)); + player.button_color_right = static_cast<u32>( + ReadIntegerSetting(std::string(player_prefix).append("button_color_right"), + Settings::JOYCON_BUTTONS_NEON_RED)); + } +} + +void Config::ReadTouchscreenValues() { + Settings::values.touchscreen.enabled = + ReadBooleanSetting(std::string("touchscreen_enabled"), std::make_optional(true)); + Settings::values.touchscreen.rotation_angle = + static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_angle"), 0)); + Settings::values.touchscreen.diameter_x = + static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_x"), 15)); + Settings::values.touchscreen.diameter_y = + static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_y"), 15)); +} + +void Config::ReadAudioValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Audio)); + + ReadCategory(Settings::Category::Audio); + ReadCategory(Settings::Category::UiAudio); + + EndGroup(); +} + +void Config::ReadControlValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + ReadCategory(Settings::Category::Controls); + + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { + ReadPlayerValues(p); + } + + // Disable docked mode if handheld is selected + const auto controller_type = Settings::values.players.GetValue()[0].controller_type; + if (controller_type == Settings::ControllerType::Handheld) { + Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig()); + Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); + } + + if (IsCustomConfig()) { + EndGroup(); + return; + } + ReadTouchscreenValues(); + ReadMotionTouchValues(); + + EndGroup(); +} + +void Config::ReadMotionTouchValues() { + int num_touch_from_button_maps = BeginArray(std::string("touch_from_button_maps")); + + if (num_touch_from_button_maps > 0) { + for (int i = 0; i < num_touch_from_button_maps; ++i) { + SetArrayIndex(i); + + Settings::TouchFromButtonMap map; + map.name = ReadStringSetting(std::string("name"), std::string("default")); + + const int num_touch_maps = BeginArray(std::string("entries")); + map.buttons.reserve(num_touch_maps); + for (int j = 0; j < num_touch_maps; j++) { + SetArrayIndex(j); + std::string touch_mapping = ReadStringSetting(std::string("bind")); + map.buttons.emplace_back(std::move(touch_mapping)); + } + EndArray(); // entries + Settings::values.touch_from_button_maps.emplace_back(std::move(map)); + } + } else { + Settings::values.touch_from_button_maps.emplace_back( + Settings::TouchFromButtonMap{"default", {}}); + num_touch_from_button_maps = 1; + } + EndArray(); // touch_from_button_maps + + Settings::values.touch_from_button_map_index = std::clamp( + Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); +} + +void Config::ReadCoreValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Core)); + + ReadCategory(Settings::Category::Core); + + EndGroup(); +} + +void Config::ReadDataStorageValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); + + FS::SetYuzuPath(FS::YuzuPath::NANDDir, ReadStringSetting(std::string("nand_directory"))); + FS::SetYuzuPath(FS::YuzuPath::SDMCDir, ReadStringSetting(std::string("sdmc_directory"))); + FS::SetYuzuPath(FS::YuzuPath::LoadDir, ReadStringSetting(std::string("load_directory"))); + FS::SetYuzuPath(FS::YuzuPath::DumpDir, ReadStringSetting(std::string("dump_directory"))); + FS::SetYuzuPath(FS::YuzuPath::TASDir, ReadStringSetting(std::string("tas_directory"))); + + ReadCategory(Settings::Category::DataStorage); + + EndGroup(); +} + +void Config::ReadDebuggingValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging)); + + // Intentionally not using the QT default setting as this is intended to be changed in the ini + Settings::values.record_frame_times = + ReadBooleanSetting(std::string("record_frame_times"), std::make_optional(false)); + + ReadCategory(Settings::Category::Debugging); + ReadCategory(Settings::Category::DebuggingGraphics); + + EndGroup(); +} + +void Config::ReadServiceValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Services)); + + ReadCategory(Settings::Category::Services); + + EndGroup(); +} + +void Config::ReadDisabledAddOnValues() { + // Custom config section + BeginGroup(std::string("DisabledAddOns")); + + const int size = BeginArray(std::string("")); + for (int i = 0; i < size; ++i) { + SetArrayIndex(i); + const auto title_id = ReadUnsignedIntegerSetting(std::string("title_id"), 0); + std::vector<std::string> out; + const int d_size = BeginArray("disabled"); + for (int j = 0; j < d_size; ++j) { + SetArrayIndex(j); + out.push_back(ReadStringSetting(std::string("d"), std::string(""))); + } + EndArray(); // d + Settings::values.disabled_addons.insert_or_assign(title_id, out); + } + EndArray(); // Base disabled addons array - Has no base key + + EndGroup(); +} + +void Config::ReadMiscellaneousValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Miscellaneous)); + + ReadCategory(Settings::Category::Miscellaneous); + + EndGroup(); +} + +void Config::ReadCpuValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Cpu)); + + ReadCategory(Settings::Category::Cpu); + ReadCategory(Settings::Category::CpuDebug); + ReadCategory(Settings::Category::CpuUnsafe); + + EndGroup(); +} + +void Config::ReadRendererValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Renderer)); + + ReadCategory(Settings::Category::Renderer); + ReadCategory(Settings::Category::RendererAdvanced); + ReadCategory(Settings::Category::RendererDebug); + + EndGroup(); +} + +void Config::ReadScreenshotValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots)); + + ReadCategory(Settings::Category::Screenshots); + FS::SetYuzuPath(FS::YuzuPath::ScreenshotsDir, + ReadStringSetting(std::string("screenshot_path"))); + + EndGroup(); +} + +void Config::ReadSystemValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::System)); + + ReadCategory(Settings::Category::System); + ReadCategory(Settings::Category::SystemAudio); + + EndGroup(); +} + +void Config::ReadWebServiceValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::WebService)); + + ReadCategory(Settings::Category::WebService); + + EndGroup(); +} + +void Config::ReadNetworkValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Services)); + + ReadCategory(Settings::Category::Network); + + EndGroup(); +} + +void Config::ReadValues() { + if (global) { + ReadDataStorageValues(); + ReadDebuggingValues(); + ReadDisabledAddOnValues(); + ReadNetworkValues(); + ReadServiceValues(); + ReadWebServiceValues(); + ReadMiscellaneousValues(); + } + ReadControlValues(); + ReadCoreValues(); + ReadCpuValues(); + ReadRendererValues(); + ReadAudioValues(); + ReadSystemValues(); +} + +void Config::SavePlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix = std::string("player_").append(ToString(player_index)).append("_"); + } + + const auto& player = Settings::values.players.GetValue()[player_index]; + if (IsCustomConfig()) { + if (player.profile_name.empty()) { + // No custom profile selected + return; + } + WriteSetting(std::string(player_prefix).append("profile_name"), player.profile_name, + std::make_optional(std::string(""))); + } + + WriteSetting(std::string(player_prefix).append("type"), static_cast<u8>(player.controller_type), + std::make_optional(static_cast<u8>(Settings::ControllerType::ProController))); + + if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) { + WriteSetting(std::string(player_prefix).append("connected"), player.connected, + std::make_optional(player_index == 0)); + WriteSetting(std::string(player_prefix).append("vibration_enabled"), + player.vibration_enabled, std::make_optional(true)); + WriteSetting(std::string(player_prefix).append("vibration_strength"), + player.vibration_strength, std::make_optional(100)); + WriteSetting(std::string(player_prefix).append("body_color_left"), player.body_color_left, + std::make_optional(Settings::JOYCON_BODY_NEON_BLUE)); + WriteSetting(std::string(player_prefix).append("body_color_right"), player.body_color_right, + std::make_optional(Settings::JOYCON_BODY_NEON_RED)); + WriteSetting(std::string(player_prefix).append("button_color_left"), + player.button_color_left, + std::make_optional(Settings::JOYCON_BUTTONS_NEON_BLUE)); + WriteSetting(std::string(player_prefix).append("button_color_right"), + player.button_color_right, + std::make_optional(Settings::JOYCON_BUTTONS_NEON_RED)); + } +} + +void Config::SaveTouchscreenValues() { + const auto& touchscreen = Settings::values.touchscreen; + + WriteSetting(std::string("touchscreen_enabled"), touchscreen.enabled, std::make_optional(true)); + + WriteSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle, + std::make_optional(static_cast<u32>(0))); + WriteSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x, + std::make_optional(static_cast<u32>(15))); + WriteSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y, + std::make_optional(static_cast<u32>(15))); +} + +void Config::SaveMotionTouchValues() { + BeginArray(std::string("touch_from_button_maps")); + for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { + SetArrayIndex(static_cast<int>(p)); + WriteSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name, + std::make_optional(std::string("default"))); + + BeginArray(std::string("entries")); + for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); + ++q) { + SetArrayIndex(static_cast<int>(q)); + WriteSetting(std::string("bind"), + Settings::values.touch_from_button_maps[p].buttons[q]); + } + EndArray(); // entries + } + EndArray(); // touch_from_button_maps +} + +void Config::SaveValues() { + if (global) { + SaveDataStorageValues(); + SaveDebuggingValues(); + SaveDisabledAddOnValues(); + SaveNetworkValues(); + SaveWebServiceValues(); + SaveMiscellaneousValues(); + } + SaveControlValues(); + SaveCoreValues(); + SaveCpuValues(); + SaveRendererValues(); + SaveAudioValues(); + SaveSystemValues(); + + WriteToIni(); +} + +void Config::SaveAudioValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Audio)); + + WriteCategory(Settings::Category::Audio); + WriteCategory(Settings::Category::UiAudio); + + EndGroup(); +} + +void Config::SaveControlValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + WriteCategory(Settings::Category::Controls); + + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { + SavePlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + SaveTouchscreenValues(); + SaveMotionTouchValues(); + + EndGroup(); +} + +void Config::SaveCoreValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Core)); + + WriteCategory(Settings::Category::Core); + + EndGroup(); +} + +void Config::SaveDataStorageValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); + + WriteSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir), + std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); + WriteSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir), + std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); + WriteSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir), + std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); + WriteSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir), + std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); + WriteSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir), + std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); + + WriteCategory(Settings::Category::DataStorage); + + EndGroup(); +} + +void Config::SaveDebuggingValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging)); + + // Intentionally not using the QT default setting as this is intended to be changed in the ini + WriteSetting(std::string("record_frame_times"), Settings::values.record_frame_times); + + WriteCategory(Settings::Category::Debugging); + WriteCategory(Settings::Category::DebuggingGraphics); + + EndGroup(); +} + +void Config::SaveNetworkValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Services)); + + WriteCategory(Settings::Category::Network); + + EndGroup(); +} + +void Config::SaveDisabledAddOnValues() { + // Custom config section + BeginGroup(std::string("DisabledAddOns")); + + int i = 0; + BeginArray(std::string("")); + for (const auto& elem : Settings::values.disabled_addons) { + SetArrayIndex(i); + WriteSetting(std::string("title_id"), elem.first, std::make_optional(static_cast<u64>(0))); + BeginArray(std::string("disabled")); + for (std::size_t j = 0; j < elem.second.size(); ++j) { + SetArrayIndex(static_cast<int>(j)); + WriteSetting(std::string("d"), elem.second[j], std::make_optional(std::string(""))); + } + EndArray(); // disabled + ++i; + } + EndArray(); // Base disabled addons array - Has no base key + + EndGroup(); +} + +void Config::SaveMiscellaneousValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Miscellaneous)); + + WriteCategory(Settings::Category::Miscellaneous); + + EndGroup(); +} + +void Config::SaveCpuValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Cpu)); + + WriteCategory(Settings::Category::Cpu); + WriteCategory(Settings::Category::CpuDebug); + WriteCategory(Settings::Category::CpuUnsafe); + + EndGroup(); +} + +void Config::SaveRendererValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Renderer)); + + WriteCategory(Settings::Category::Renderer); + WriteCategory(Settings::Category::RendererAdvanced); + WriteCategory(Settings::Category::RendererDebug); + + EndGroup(); +} + +void Config::SaveScreenshotValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots)); + + WriteSetting(std::string("screenshot_path"), + FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)); + WriteCategory(Settings::Category::Screenshots); + + EndGroup(); +} + +void Config::SaveSystemValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::System)); + + WriteCategory(Settings::Category::System); + WriteCategory(Settings::Category::SystemAudio); + + EndGroup(); +} + +void Config::SaveWebServiceValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::WebService)); + + WriteCategory(Settings::Category::WebService); + + EndGroup(); +} + +bool Config::ReadBooleanSetting(const std::string& key, const std::optional<bool> default_value) { + std::string full_key = GetFullKey(key, false); + if (!default_value.has_value()) { + return config->GetBoolValue(GetSection().c_str(), full_key.c_str(), false); + } + + if (config->GetBoolValue(GetSection().c_str(), + std::string(full_key).append("\\default").c_str(), false)) { + return static_cast<bool>(default_value.value()); + } else { + return config->GetBoolValue(GetSection().c_str(), full_key.c_str(), + static_cast<bool>(default_value.value())); + } +} + +s64 Config::ReadIntegerSetting(const std::string& key, const std::optional<s64> default_value) { + std::string full_key = GetFullKey(key, false); + if (!default_value.has_value()) { + try { + return std::stoll( + std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0"))); + } catch (...) { + return 0; + } + } + + s64 result = 0; + if (config->GetBoolValue(GetSection().c_str(), + std::string(full_key).append("\\default").c_str(), true)) { + result = default_value.value(); + } else { + try { + result = std::stoll(std::string(config->GetValue( + GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str()))); + } catch (...) { + result = default_value.value(); + } + } + return result; +} + +u64 Config::ReadUnsignedIntegerSetting(const std::string& key, + const std::optional<u64> default_value) { + std::string full_key = GetFullKey(key, false); + if (!default_value.has_value()) { + try { + return std::stoull( + std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0"))); + } catch (...) { + return 0; + } + } + + u64 result = 0; + if (config->GetBoolValue(GetSection().c_str(), + std::string(full_key).append("\\default").c_str(), true)) { + result = default_value.value(); + } else { + try { + result = std::stoull(std::string(config->GetValue( + GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str()))); + } catch (...) { + result = default_value.value(); + } + } + return result; +} + +double Config::ReadDoubleSetting(const std::string& key, + const std::optional<double> default_value) { + std::string full_key = GetFullKey(key, false); + if (!default_value.has_value()) { + return config->GetDoubleValue(GetSection().c_str(), full_key.c_str(), 0); + } + + double result; + if (config->GetBoolValue(GetSection().c_str(), + std::string(full_key).append("\\default").c_str(), true)) { + result = default_value.value(); + } else { + result = + config->GetDoubleValue(GetSection().c_str(), full_key.c_str(), default_value.value()); + } + return result; +} + +std::string Config::ReadStringSetting(const std::string& key, + const std::optional<std::string> default_value) { + std::string result; + std::string full_key = GetFullKey(key, false); + if (!default_value.has_value()) { + result = config->GetValue(GetSection().c_str(), full_key.c_str(), ""); + boost::replace_all(result, "\"", ""); + return result; + } + + if (config->GetBoolValue(GetSection().c_str(), + std::string(full_key).append("\\default").c_str(), true)) { + result = default_value.value(); + } else { + result = + config->GetValue(GetSection().c_str(), full_key.c_str(), default_value.value().c_str()); + } + boost::replace_all(result, "\"", ""); + boost::replace_all(result, "//", "/"); + return result; +} + +bool Config::Exists(const std::string& section, const std::string& key) const { + const std::string value = config->GetValue(section.c_str(), key.c_str(), ""); + return !value.empty(); +} + +template <typename Type> +void Config::WriteSetting(const std::string& key, const Type& value, + const std::optional<Type>& default_value, + const std::optional<bool>& use_global) { + std::string full_key = GetFullKey(key, false); + + std::string saved_value; + std::string string_default; + if constexpr (std::is_same_v<Type, std::string>) { + saved_value.append(AdjustOutputString(value)); + if (default_value.has_value()) { + string_default.append(AdjustOutputString(default_value.value())); + } + } else { + saved_value.append(AdjustOutputString(ToString(value))); + if (default_value.has_value()) { + string_default.append(ToString(default_value.value())); + } + } + + if (default_value.has_value() && use_global.has_value()) { + if (!global) { + WriteSettingInternal(std::string(full_key).append("\\global"), + ToString(use_global.value())); + } + if (global || use_global.value() == false) { + WriteSettingInternal(std::string(full_key).append("\\default"), + ToString(string_default == saved_value)); + WriteSettingInternal(full_key, saved_value); + } + } else if (default_value.has_value() && !use_global.has_value()) { + WriteSettingInternal(std::string(full_key).append("\\default"), + ToString(string_default == saved_value)); + WriteSettingInternal(full_key, saved_value); + } else { + WriteSettingInternal(full_key, saved_value); + } +} + +void Config::WriteSettingInternal(const std::string& key, const std::string& value) { + config->SetValue(GetSection().c_str(), key.c_str(), value.c_str()); +} + +void Config::Reload() { + ReadValues(); + // To apply default value changes + SaveValues(); +} + +void Config::Save() { + SaveValues(); +} + +void Config::ClearControlPlayerValues() const { + // If key is an empty string, all keys in the current group() are removed. + const char* section = Settings::TranslateCategory(Settings::Category::Controls); + CSimpleIniA::TNamesDepend keys; + config->GetAllKeys(section, keys); + for (const auto& key : keys) { + if (std::string(config->GetValue(section, key.pItem)).empty()) { + config->Delete(section, key.pItem); + } + } +} + +const std::string& Config::GetConfigFilePath() const { + return config_loc; +} + +void Config::ReadCategory(const Settings::Category category) { + const auto& settings = FindRelevantList(category); + std::ranges::for_each(settings, [&](const auto& setting) { ReadSettingGeneric(setting); }); +} + +void Config::WriteCategory(const Settings::Category category) { + const auto& settings = FindRelevantList(category); + std::ranges::for_each(settings, [&](const auto& setting) { WriteSettingGeneric(setting); }); +} + +void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) { + if (!setting->Save() || (!setting->Switchable() && !global)) { + return; + } + + const std::string key = AdjustKey(setting->GetLabel()); + const std::string default_value(setting->DefaultToString()); + + bool use_global = true; + if (setting->Switchable() && !global) { + use_global = + ReadBooleanSetting(std::string(key).append("\\use_global"), std::make_optional(true)); + setting->SetGlobal(use_global); + } + + if (global || !use_global) { + const bool is_default = + ReadBooleanSetting(std::string(key).append("\\default"), std::make_optional(true)); + if (!is_default) { + const std::string setting_string = ReadStringSetting(key, default_value); + setting->LoadString(setting_string); + } else { + // Empty string resets the Setting to default + setting->LoadString(""); + } + } +} + +void Config::WriteSettingGeneric(const Settings::BasicSetting* const setting) { + if (!setting->Save()) { + return; + } + + std::string key = AdjustKey(setting->GetLabel()); + if (setting->Switchable()) { + if (!global) { + WriteSetting(std::string(key).append("\\use_global"), setting->UsingGlobal()); + } + if (global || !setting->UsingGlobal()) { + WriteSetting(std::string(key).append("\\default"), + setting->ToString() == setting->DefaultToString()); + WriteSetting(key, setting->ToString()); + } + } else if (global) { + WriteSetting(std::string(key).append("\\default"), + setting->ToString() == setting->DefaultToString()); + WriteSetting(key, setting->ToString()); + } +} + +void Config::BeginGroup(const std::string& group) { + // You can't begin a group while reading/writing from a config array + ASSERT(array_stack.empty()); + + key_stack.push_back(AdjustKey(group)); +} + +void Config::EndGroup() { + // You can't end a group if you haven't started one yet + ASSERT(!key_stack.empty()); + + // You can't end a group when reading/writing from a config array + ASSERT(array_stack.empty()); + + key_stack.pop_back(); +} + +std::string Config::GetSection() { + if (key_stack.empty()) { + return std::string{""}; + } + + return key_stack.front(); +} + +std::string Config::GetGroup() const { + if (key_stack.size() <= 1) { + return std::string{""}; + } + + std::string key; + for (size_t i = 1; i < key_stack.size(); ++i) { + key.append(key_stack[i]).append("\\"); + } + return key; +} + +std::string Config::AdjustKey(const std::string& key) { + std::string adjusted_key(key); + boost::replace_all(adjusted_key, "/", "\\"); + boost::replace_all(adjusted_key, " ", "%20"); + return adjusted_key; +} + +std::string Config::AdjustOutputString(const std::string& string) { + std::string adjusted_string(string); + boost::replace_all(adjusted_string, "\\", "/"); + + // Windows requires that two forward slashes are used at the start of a path for unmapped + // network drives so we have to watch for that here + if (string.substr(0, 2) == "//") { + boost::replace_all(adjusted_string, "//", "/"); + adjusted_string.insert(0, "/"); + } else { + boost::replace_all(adjusted_string, "//", "/"); + } + + // Needed for backwards compatibility with QSettings deserialization + for (const auto& special_character : special_characters) { + if (adjusted_string.find(special_character) != std::string::npos) { + adjusted_string.insert(0, "\""); + adjusted_string.append("\""); + break; + } + } + return adjusted_string; +} + +std::string Config::GetFullKey(const std::string& key, bool skipArrayIndex) { + if (array_stack.empty()) { + return std::string(GetGroup()).append(AdjustKey(key)); + } + + std::string array_key; + for (size_t i = 0; i < array_stack.size(); ++i) { + if (!array_stack[i].name.empty()) { + array_key.append(array_stack[i].name).append("\\"); + } + + if (!skipArrayIndex || (array_stack.size() - 1 != i && array_stack.size() > 1)) { + array_key.append(ToString(array_stack[i].index)).append("\\"); + } + } + std::string final_key = std::string(GetGroup()).append(array_key).append(AdjustKey(key)); + return final_key; +} + +int Config::BeginArray(const std::string& array) { + array_stack.push_back(ConfigArray{AdjustKey(array), 0, 0}); + const int size = config->GetLongValue(GetSection().c_str(), + GetFullKey(std::string("size"), true).c_str(), 0); + array_stack.back().size = size; + return size; +} + +void Config::EndArray() { + // You can't end a config array before starting one + ASSERT(!array_stack.empty()); + + // Set the array size to 0 if the array is ended without changing the index + int size = 0; + if (array_stack.back().index != 0) { + size = array_stack.back().size; + } + + // Write out the size to config + if (key_stack.size() == 1 && array_stack.back().name.empty()) { + // Edge-case where the first array created doesn't have a name + config->SetValue(GetSection().c_str(), std::string("size").c_str(), ToString(size).c_str()); + } else { + const auto key = GetFullKey(std::string("size"), true); + config->SetValue(GetSection().c_str(), key.c_str(), ToString(size).c_str()); + } + + array_stack.pop_back(); +} + +void Config::SetArrayIndex(const int index) { + // You can't set the array index if you haven't started one yet + ASSERT(!array_stack.empty()); + + const int array_index = index + 1; + + // You can't exceed the known max size of the array by more than 1 + ASSERT(array_stack.front().size + 1 >= array_index); + + // Change the config array size to the current index since you may want + // to reduce the number of elements that you read back from the config + // in the future. + array_stack.back().size = array_index; + array_stack.back().index = array_index; +} diff --git a/src/frontend_common/config.h b/src/frontend_common/config.h new file mode 100644 index 000000000..20a1a8056 --- /dev/null +++ b/src/frontend_common/config.h @@ -0,0 +1,210 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> +#include <string> +#include "common/settings.h" + +#include <SimpleIni.h> +#include <boost/algorithm/string/replace.hpp> + +// Workaround for conflicting definition in libloaderapi.h caused by SimpleIni +#undef LoadString +#undef CreateFile +#undef DeleteFile +#undef CopyFile +#undef CreateDirectory +#undef MoveFile + +namespace Core { +class System; +} + +class Config { +public: + enum class ConfigType { + GlobalConfig, + PerGameConfig, + InputProfile, + }; + + virtual ~Config() = default; + + void ClearControlPlayerValues() const; + + [[nodiscard]] const std::string& GetConfigFilePath() const; + + [[nodiscard]] bool Exists(const std::string& section, const std::string& key) const; + +protected: + explicit Config(ConfigType config_type = ConfigType::GlobalConfig); + + void Initialize(const std::string& config_name = "config"); + void Initialize(std::optional<std::string> config_path); + + void WriteToIni() const; + + void SetUpIni(); + [[nodiscard]] bool IsCustomConfig() const; + + void Reload(); + void Save(); + + /** + * Derived config classes must implement this so they can reload all platform-specific + * values and global ones. + */ + virtual void ReloadAllValues() = 0; + + /** + * Derived config classes must implement this so they can save all platform-specific + * and global values. + */ + virtual void SaveAllValues() = 0; + + void ReadValues(); + void ReadPlayerValues(std::size_t player_index); + + void ReadTouchscreenValues(); + void ReadMotionTouchValues(); + + // Read functions bases off the respective config section names. + void ReadAudioValues(); + void ReadControlValues(); + void ReadCoreValues(); + void ReadDataStorageValues(); + void ReadDebuggingValues(); + void ReadServiceValues(); + void ReadDisabledAddOnValues(); + void ReadMiscellaneousValues(); + void ReadCpuValues(); + void ReadRendererValues(); + void ReadScreenshotValues(); + void ReadSystemValues(); + void ReadWebServiceValues(); + void ReadNetworkValues(); + + // Read platform specific sections + virtual void ReadHidbusValues() = 0; + virtual void ReadDebugControlValues() = 0; + virtual void ReadPathValues() = 0; + virtual void ReadShortcutValues() = 0; + virtual void ReadUIValues() = 0; + virtual void ReadUIGamelistValues() = 0; + virtual void ReadUILayoutValues() = 0; + virtual void ReadMultiplayerValues() = 0; + + void SaveValues(); + void SavePlayerValues(std::size_t player_index); + void SaveTouchscreenValues(); + void SaveMotionTouchValues(); + + // Save functions based off the respective config section names. + void SaveAudioValues(); + void SaveControlValues(); + void SaveCoreValues(); + void SaveDataStorageValues(); + void SaveDebuggingValues(); + void SaveNetworkValues(); + void SaveDisabledAddOnValues(); + void SaveMiscellaneousValues(); + void SaveCpuValues(); + void SaveRendererValues(); + void SaveScreenshotValues(); + void SaveSystemValues(); + void SaveWebServiceValues(); + + // Save platform specific sections + virtual void SaveHidbusValues() = 0; + virtual void SaveDebugControlValues() = 0; + virtual void SavePathValues() = 0; + virtual void SaveShortcutValues() = 0; + virtual void SaveUIValues() = 0; + virtual void SaveUIGamelistValues() = 0; + virtual void SaveUILayoutValues() = 0; + virtual void SaveMultiplayerValues() = 0; + + virtual std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) = 0; + + /** + * Reads a setting from the qt_config. + * + * @param key The setting's identifier + * @param default_value The value to use when the setting is not already present in the config + */ + bool ReadBooleanSetting(const std::string& key, + std::optional<bool> default_value = std::nullopt); + s64 ReadIntegerSetting(const std::string& key, std::optional<s64> default_value = std::nullopt); + u64 ReadUnsignedIntegerSetting(const std::string& key, + std::optional<u64> default_value = std::nullopt); + double ReadDoubleSetting(const std::string& key, + std::optional<double> default_value = std::nullopt); + std::string ReadStringSetting(const std::string& key, + std::optional<std::string> default_value = std::nullopt); + + /** + * Writes a setting to the qt_config. + * + * @param key The setting's idetentifier + * @param value Value of the setting + * @param default_value Default of the setting if not present in config + * @param use_global Specifies if the custom or global config should be in use, for custom + * configs + */ + template <typename Type = int> + void WriteSetting(const std::string& key, const Type& value, + const std::optional<Type>& default_value = std::nullopt, + const std::optional<bool>& use_global = std::nullopt); + void WriteSettingInternal(const std::string& key, const std::string& value); + + void ReadCategory(Settings::Category category); + void WriteCategory(Settings::Category category); + void ReadSettingGeneric(Settings::BasicSetting* setting); + void WriteSettingGeneric(const Settings::BasicSetting* setting); + + template <typename T> + [[nodiscard]] std::string ToString(const T& value_) { + if constexpr (std::is_same_v<T, std::string>) { + return value_; + } else if constexpr (std::is_same_v<T, std::optional<u32>>) { + return value_.has_value() ? std::to_string(*value_) : "none"; + } else if constexpr (std::is_same_v<T, bool>) { + return value_ ? "true" : "false"; + } else if constexpr (std::is_same_v<T, u64>) { + return std::to_string(static_cast<u64>(value_)); + } else { + return std::to_string(static_cast<s64>(value_)); + } + } + + void BeginGroup(const std::string& group); + void EndGroup(); + std::string GetSection(); + [[nodiscard]] std::string GetGroup() const; + static std::string AdjustKey(const std::string& key); + static std::string AdjustOutputString(const std::string& string); + std::string GetFullKey(const std::string& key, bool skipArrayIndex); + int BeginArray(const std::string& array); + void EndArray(); + void SetArrayIndex(int index); + + const ConfigType type; + std::unique_ptr<CSimpleIniA> config; + std::string config_loc; + const bool global; + +private: + inline static std::array<char, 19> special_characters = {'!', '#', '$', '%', '^', '&', '*', + '|', ';', '\'', '\"', ',', '<', '.', + '>', '?', '`', '~', '='}; + + struct ConfigArray { + std::string name; + int size; + int index; + }; + std::vector<ConfigArray> array_stack; + std::vector<std::string> key_stack; +}; diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index cf9266d54..b65b9f2a2 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -4,7 +4,7 @@ add_subdirectory(host_shaders) if(LIBVA_FOUND) - set_source_files_properties(host1x/codecs/codec.cpp + set_source_files_properties(host1x/ffmpeg/ffmpeg.cpp PROPERTIES COMPILE_DEFINITIONS LIBVA_FOUND=1) list(APPEND FFmpeg_LIBRARIES ${LIBVA_LIBRARIES}) endif() @@ -66,6 +66,8 @@ add_library(video_core STATIC host1x/codecs/vp9.cpp host1x/codecs/vp9.h host1x/codecs/vp9_types.h + host1x/ffmpeg/ffmpeg.cpp + host1x/ffmpeg/ffmpeg.h host1x/control.cpp host1x/control.h host1x/host1x.cpp diff --git a/src/video_core/host1x/codecs/codec.cpp b/src/video_core/host1x/codecs/codec.cpp index dbcf508e5..1030db681 100644 --- a/src/video_core/host1x/codecs/codec.cpp +++ b/src/video_core/host1x/codecs/codec.cpp @@ -1,11 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <algorithm> -#include <fstream> -#include <vector> #include "common/assert.h" -#include "common/scope_exit.h" #include "common/settings.h" #include "video_core/host1x/codecs/codec.h" #include "video_core/host1x/codecs/h264.h" @@ -14,242 +10,17 @@ #include "video_core/host1x/host1x.h" #include "video_core/memory_manager.h" -extern "C" { -#include <libavfilter/buffersink.h> -#include <libavfilter/buffersrc.h> -#include <libavutil/opt.h> -#ifdef LIBVA_FOUND -// for querying VAAPI driver information -#include <libavutil/hwcontext_vaapi.h> -#endif -} - namespace Tegra { -namespace { -constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12; -constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P; -constexpr std::array PREFERRED_GPU_DECODERS = { - AV_HWDEVICE_TYPE_CUDA, -#ifdef _WIN32 - AV_HWDEVICE_TYPE_D3D11VA, - AV_HWDEVICE_TYPE_DXVA2, -#elif defined(__unix__) - AV_HWDEVICE_TYPE_VAAPI, - AV_HWDEVICE_TYPE_VDPAU, -#endif - // last resort for Linux Flatpak (w/ NVIDIA) - AV_HWDEVICE_TYPE_VULKAN, -}; - -void AVPacketDeleter(AVPacket* ptr) { - av_packet_free(&ptr); -} - -using AVPacketPtr = std::unique_ptr<AVPacket, decltype(&AVPacketDeleter)>; - -AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pix_fmts) { - for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) { - if (*p == av_codec_ctx->pix_fmt) { - return av_codec_ctx->pix_fmt; - } - } - LOG_INFO(Service_NVDRV, "Could not find compatible GPU AV format, falling back to CPU"); - av_buffer_unref(&av_codec_ctx->hw_device_ctx); - av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT; - return PREFERRED_CPU_FMT; -} - -// List all the currently available hwcontext in ffmpeg -std::vector<AVHWDeviceType> ListSupportedContexts() { - std::vector<AVHWDeviceType> contexts{}; - AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; - do { - current_device_type = av_hwdevice_iterate_types(current_device_type); - contexts.push_back(current_device_type); - } while (current_device_type != AV_HWDEVICE_TYPE_NONE); - return contexts; -} - -} // namespace - -void AVFrameDeleter(AVFrame* ptr) { - av_frame_free(&ptr); -} Codec::Codec(Host1x::Host1x& host1x_, const Host1x::NvdecCommon::NvdecRegisters& regs) : host1x(host1x_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(host1x)), vp8_decoder(std::make_unique<Decoder::VP8>(host1x)), vp9_decoder(std::make_unique<Decoder::VP9>(host1x)) {} -Codec::~Codec() { - if (!initialized) { - return; - } - // Free libav memory - avcodec_free_context(&av_codec_ctx); - av_buffer_unref(&av_gpu_decoder); - - if (filters_initialized) { - avfilter_graph_free(&av_filter_graph); - } -} - -bool Codec::CreateGpuAvDevice() { - static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX; - static const auto supported_contexts = ListSupportedContexts(); - for (const auto& type : PREFERRED_GPU_DECODERS) { - if (std::none_of(supported_contexts.begin(), supported_contexts.end(), - [&type](const auto& context) { return context == type; })) { - LOG_DEBUG(Service_NVDRV, "{} explicitly unsupported", av_hwdevice_get_type_name(type)); - continue; - } - // Avoid memory leak from not cleaning up after av_hwdevice_ctx_create - av_buffer_unref(&av_gpu_decoder); - const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0); - if (hwdevice_res < 0) { - LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}", - av_hwdevice_get_type_name(type), hwdevice_res); - continue; - } -#ifdef LIBVA_FOUND - if (type == AV_HWDEVICE_TYPE_VAAPI) { - // we need to determine if this is an impersonated VAAPI driver - AVHWDeviceContext* hwctx = - static_cast<AVHWDeviceContext*>(static_cast<void*>(av_gpu_decoder->data)); - AVVAAPIDeviceContext* vactx = static_cast<AVVAAPIDeviceContext*>(hwctx->hwctx); - const char* vendor_name = vaQueryVendorString(vactx->display); - if (strstr(vendor_name, "VDPAU backend")) { - // VDPAU impersonated VAAPI impl's are super buggy, we need to skip them - LOG_DEBUG(Service_NVDRV, "Skipping vdapu impersonated VAAPI driver"); - continue; - } else { - // according to some user testing, certain vaapi driver (Intel?) could be buggy - // so let's log the driver name which may help the developers/supporters - LOG_DEBUG(Service_NVDRV, "Using VAAPI driver: {}", vendor_name); - } - } -#endif - for (int i = 0;; i++) { - const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i); - if (!config) { - LOG_DEBUG(Service_NVDRV, "{} decoder does not support device type {}.", - av_codec->name, av_hwdevice_get_type_name(type)); - break; - } - if ((config->methods & HW_CONFIG_METHOD) != 0 && config->device_type == type) { - LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type)); - av_codec_ctx->pix_fmt = config->pix_fmt; - return true; - } - } - } - return false; -} - -void Codec::InitializeAvCodecContext() { - av_codec_ctx = avcodec_alloc_context3(av_codec); - av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0); - av_codec_ctx->thread_count = 0; - av_codec_ctx->thread_type &= ~FF_THREAD_FRAME; -} - -void Codec::InitializeGpuDecoder() { - if (!CreateGpuAvDevice()) { - av_buffer_unref(&av_gpu_decoder); - return; - } - auto* hw_device_ctx = av_buffer_ref(av_gpu_decoder); - ASSERT_MSG(hw_device_ctx, "av_buffer_ref failed"); - av_codec_ctx->hw_device_ctx = hw_device_ctx; - av_codec_ctx->get_format = GetGpuFormat; -} - -void Codec::InitializeAvFilters(AVFrame* frame) { - const AVFilter* buffer_src = avfilter_get_by_name("buffer"); - const AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); - AVFilterInOut* inputs = avfilter_inout_alloc(); - AVFilterInOut* outputs = avfilter_inout_alloc(); - SCOPE_EXIT({ - avfilter_inout_free(&inputs); - avfilter_inout_free(&outputs); - }); - - // Don't know how to get the accurate time_base but it doesn't matter for yadif filter - // so just use 1/1 to make buffer filter happy - std::string args = fmt::format("video_size={}x{}:pix_fmt={}:time_base=1/1", frame->width, - frame->height, frame->format); - - av_filter_graph = avfilter_graph_alloc(); - int ret = avfilter_graph_create_filter(&av_filter_src_ctx, buffer_src, "in", args.c_str(), - nullptr, av_filter_graph); - if (ret < 0) { - LOG_ERROR(Service_NVDRV, "avfilter_graph_create_filter source error: {}", ret); - return; - } - - ret = avfilter_graph_create_filter(&av_filter_sink_ctx, buffer_sink, "out", nullptr, nullptr, - av_filter_graph); - if (ret < 0) { - LOG_ERROR(Service_NVDRV, "avfilter_graph_create_filter sink error: {}", ret); - return; - } - - inputs->name = av_strdup("out"); - inputs->filter_ctx = av_filter_sink_ctx; - inputs->pad_idx = 0; - inputs->next = nullptr; - - outputs->name = av_strdup("in"); - outputs->filter_ctx = av_filter_src_ctx; - outputs->pad_idx = 0; - outputs->next = nullptr; - - const char* description = "yadif=1:-1:0"; - ret = avfilter_graph_parse_ptr(av_filter_graph, description, &inputs, &outputs, nullptr); - if (ret < 0) { - LOG_ERROR(Service_NVDRV, "avfilter_graph_parse_ptr error: {}", ret); - return; - } - - ret = avfilter_graph_config(av_filter_graph, nullptr); - if (ret < 0) { - LOG_ERROR(Service_NVDRV, "avfilter_graph_config error: {}", ret); - return; - } - - filters_initialized = true; -} +Codec::~Codec() = default; void Codec::Initialize() { - const AVCodecID codec = [&] { - switch (current_codec) { - case Host1x::NvdecCommon::VideoCodec::H264: - return AV_CODEC_ID_H264; - case Host1x::NvdecCommon::VideoCodec::VP8: - return AV_CODEC_ID_VP8; - case Host1x::NvdecCommon::VideoCodec::VP9: - return AV_CODEC_ID_VP9; - default: - UNIMPLEMENTED_MSG("Unknown codec {}", current_codec); - return AV_CODEC_ID_NONE; - } - }(); - av_codec = avcodec_find_decoder(codec); - - InitializeAvCodecContext(); - if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) { - InitializeGpuDecoder(); - } - if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) { - LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed with result {}", res); - avcodec_free_context(&av_codec_ctx); - av_buffer_unref(&av_gpu_decoder); - return; - } - if (!av_codec_ctx->hw_device_ctx) { - LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding"); - } - initialized = true; + initialized = decode_api.Initialize(current_codec); } void Codec::SetTargetCodec(Host1x::NvdecCommon::VideoCodec codec) { @@ -264,14 +35,18 @@ void Codec::Decode() { if (is_first_frame) { Initialize(); } + if (!initialized) { return; } + + // Assemble bitstream. bool vp9_hidden_frame = false; - const auto& frame_data = [&]() { + size_t configuration_size = 0; + const auto packet_data = [&]() { switch (current_codec) { case Tegra::Host1x::NvdecCommon::VideoCodec::H264: - return h264_decoder->ComposeFrame(state, is_first_frame); + return h264_decoder->ComposeFrame(state, &configuration_size, is_first_frame); case Tegra::Host1x::NvdecCommon::VideoCodec::VP8: return vp8_decoder->ComposeFrame(state); case Tegra::Host1x::NvdecCommon::VideoCodec::VP9: @@ -283,89 +58,35 @@ void Codec::Decode() { return std::span<const u8>{}; } }(); - AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter}; - if (!packet) { - LOG_ERROR(Service_NVDRV, "av_packet_alloc failed"); - return; - } - packet->data = const_cast<u8*>(frame_data.data()); - packet->size = static_cast<s32>(frame_data.size()); - if (const int res = avcodec_send_packet(av_codec_ctx, packet.get()); res != 0) { - LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", res); + + // Send assembled bitstream to decoder. + if (!decode_api.SendPacket(packet_data, configuration_size)) { return; } - // Only receive/store visible frames + + // Only receive/store visible frames. if (vp9_hidden_frame) { return; } - AVFramePtr initial_frame{av_frame_alloc(), AVFrameDeleter}; - AVFramePtr final_frame{nullptr, AVFrameDeleter}; - ASSERT_MSG(initial_frame, "av_frame_alloc initial_frame failed"); - if (const int ret = avcodec_receive_frame(av_codec_ctx, initial_frame.get()); ret) { - LOG_DEBUG(Service_NVDRV, "avcodec_receive_frame error {}", ret); - return; - } - if (initial_frame->width == 0 || initial_frame->height == 0) { - LOG_WARNING(Service_NVDRV, "Zero width or height in frame"); - return; - } - bool is_interlaced = initial_frame->interlaced_frame != 0; - if (av_codec_ctx->hw_device_ctx) { - final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter}; - ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed"); - // Can't use AV_PIX_FMT_YUV420P and share code with software decoding in vic.cpp - // because Intel drivers crash unless using AV_PIX_FMT_NV12 - final_frame->format = PREFERRED_GPU_FMT; - const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0); - ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret); - } else { - final_frame = std::move(initial_frame); - } - if (final_frame->format != PREFERRED_CPU_FMT && final_frame->format != PREFERRED_GPU_FMT) { - UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format); - return; - } - if (!is_interlaced) { - av_frames.push(std::move(final_frame)); - } else { - if (!filters_initialized) { - InitializeAvFilters(final_frame.get()); - } - if (const int ret = av_buffersrc_add_frame_flags(av_filter_src_ctx, final_frame.get(), - AV_BUFFERSRC_FLAG_KEEP_REF); - ret) { - LOG_DEBUG(Service_NVDRV, "av_buffersrc_add_frame_flags error {}", ret); - return; - } - while (true) { - auto filter_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter}; - int ret = av_buffersink_get_frame(av_filter_sink_ctx, filter_frame.get()); + // Receive output frames from decoder. + decode_api.ReceiveFrames(frames); - if (ret == AVERROR(EAGAIN) || ret == AVERROR(AVERROR_EOF)) - break; - if (ret < 0) { - LOG_DEBUG(Service_NVDRV, "av_buffersink_get_frame error {}", ret); - return; - } - - av_frames.push(std::move(filter_frame)); - } - } - while (av_frames.size() > 10) { - LOG_TRACE(Service_NVDRV, "av_frames.push overflow dropped frame"); - av_frames.pop(); + while (frames.size() > 10) { + LOG_DEBUG(HW_GPU, "ReceiveFrames overflow, dropped frame"); + frames.pop(); } } -AVFramePtr Codec::GetCurrentFrame() { +std::unique_ptr<FFmpeg::Frame> Codec::GetCurrentFrame() { // Sometimes VIC will request more frames than have been decoded. - // in this case, return a nullptr and don't overwrite previous frame data - if (av_frames.empty()) { - return AVFramePtr{nullptr, AVFrameDeleter}; + // in this case, return a blank frame and don't overwrite previous data. + if (frames.empty()) { + return {}; } - AVFramePtr frame = std::move(av_frames.front()); - av_frames.pop(); + + auto frame = std::move(frames.front()); + frames.pop(); return frame; } diff --git a/src/video_core/host1x/codecs/codec.h b/src/video_core/host1x/codecs/codec.h index 06fe00a4b..f700ae129 100644 --- a/src/video_core/host1x/codecs/codec.h +++ b/src/video_core/host1x/codecs/codec.h @@ -4,28 +4,15 @@ #pragma once #include <memory> +#include <optional> #include <string_view> #include <queue> #include "common/common_types.h" +#include "video_core/host1x/ffmpeg/ffmpeg.h" #include "video_core/host1x/nvdec_common.h" -extern "C" { -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif -#include <libavcodec/avcodec.h> -#include <libavfilter/avfilter.h> -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif -} - namespace Tegra { -void AVFrameDeleter(AVFrame* ptr); -using AVFramePtr = std::unique_ptr<AVFrame, decltype(&AVFrameDeleter)>; - namespace Decoder { class H264; class VP8; @@ -51,7 +38,7 @@ public: void Decode(); /// Returns next decoded frame - [[nodiscard]] AVFramePtr GetCurrentFrame(); + [[nodiscard]] std::unique_ptr<FFmpeg::Frame> GetCurrentFrame(); /// Returns the value of current_codec [[nodiscard]] Host1x::NvdecCommon::VideoCodec GetCurrentCodec() const; @@ -60,25 +47,9 @@ public: [[nodiscard]] std::string_view GetCurrentCodecName() const; private: - void InitializeAvCodecContext(); - - void InitializeAvFilters(AVFrame* frame); - - void InitializeGpuDecoder(); - - bool CreateGpuAvDevice(); - bool initialized{}; - bool filters_initialized{}; Host1x::NvdecCommon::VideoCodec current_codec{Host1x::NvdecCommon::VideoCodec::None}; - - const AVCodec* av_codec{nullptr}; - AVCodecContext* av_codec_ctx{nullptr}; - AVBufferRef* av_gpu_decoder{nullptr}; - - AVFilterContext* av_filter_src_ctx{nullptr}; - AVFilterContext* av_filter_sink_ctx{nullptr}; - AVFilterGraph* av_filter_graph{nullptr}; + FFmpeg::DecodeApi decode_api; Host1x::Host1x& host1x; const Host1x::NvdecCommon::NvdecRegisters& state; @@ -86,7 +57,7 @@ private: std::unique_ptr<Decoder::VP8> vp8_decoder; std::unique_ptr<Decoder::VP9> vp9_decoder; - std::queue<AVFramePtr> av_frames{}; + std::queue<std::unique_ptr<FFmpeg::Frame>> frames{}; }; } // namespace Tegra diff --git a/src/video_core/host1x/codecs/h264.cpp b/src/video_core/host1x/codecs/h264.cpp index ece79b1e2..309a7f1d5 100644 --- a/src/video_core/host1x/codecs/h264.cpp +++ b/src/video_core/host1x/codecs/h264.cpp @@ -30,7 +30,7 @@ H264::H264(Host1x::Host1x& host1x_) : host1x{host1x_} {} H264::~H264() = default; std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state, - bool is_first_frame) { + size_t* out_configuration_size, bool is_first_frame) { H264DecoderContext context; host1x.MemoryManager().ReadBlock(state.picture_info_offset, &context, sizeof(H264DecoderContext)); @@ -39,6 +39,7 @@ std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters if (!is_first_frame && frame_number != 0) { frame.resize_destructive(context.stream_len); host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size()); + *out_configuration_size = 0; return frame; } @@ -157,6 +158,7 @@ std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters frame.resize(encoded_header.size() + context.stream_len); std::memcpy(frame.data(), encoded_header.data(), encoded_header.size()); + *out_configuration_size = encoded_header.size(); host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data() + encoded_header.size(), context.stream_len); diff --git a/src/video_core/host1x/codecs/h264.h b/src/video_core/host1x/codecs/h264.h index d6b556322..1deaf4632 100644 --- a/src/video_core/host1x/codecs/h264.h +++ b/src/video_core/host1x/codecs/h264.h @@ -67,6 +67,7 @@ public: /// Compose the H264 frame for FFmpeg decoding [[nodiscard]] std::span<const u8> ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state, + size_t* out_configuration_size, bool is_first_frame = false); private: diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp new file mode 100644 index 000000000..dcd07e6d2 --- /dev/null +++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp @@ -0,0 +1,419 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/scope_exit.h" +#include "common/settings.h" +#include "video_core/host1x/ffmpeg/ffmpeg.h" + +extern "C" { +#ifdef LIBVA_FOUND +// for querying VAAPI driver information +#include <libavutil/hwcontext_vaapi.h> +#endif +} + +namespace FFmpeg { + +namespace { + +constexpr AVPixelFormat PreferredGpuFormat = AV_PIX_FMT_NV12; +constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P; +constexpr std::array PreferredGpuDecoders = { + AV_HWDEVICE_TYPE_CUDA, +#ifdef _WIN32 + AV_HWDEVICE_TYPE_D3D11VA, + AV_HWDEVICE_TYPE_DXVA2, +#elif defined(__unix__) + AV_HWDEVICE_TYPE_VAAPI, + AV_HWDEVICE_TYPE_VDPAU, +#endif + // last resort for Linux Flatpak (w/ NVIDIA) + AV_HWDEVICE_TYPE_VULKAN, +}; + +AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* pix_fmts) { + for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) { + if (*p == codec_context->pix_fmt) { + return codec_context->pix_fmt; + } + } + + LOG_INFO(HW_GPU, "Could not find compatible GPU AV format, falling back to CPU"); + av_buffer_unref(&codec_context->hw_device_ctx); + + codec_context->pix_fmt = PreferredCpuFormat; + return codec_context->pix_fmt; +} + +std::string AVError(int errnum) { + char errbuf[AV_ERROR_MAX_STRING_SIZE] = {}; + av_make_error_string(errbuf, sizeof(errbuf) - 1, errnum); + return errbuf; +} + +} // namespace + +Packet::Packet(std::span<const u8> data) { + m_packet = av_packet_alloc(); + m_packet->data = const_cast<u8*>(data.data()); + m_packet->size = static_cast<s32>(data.size()); +} + +Packet::~Packet() { + av_packet_free(&m_packet); +} + +Frame::Frame() { + m_frame = av_frame_alloc(); +} + +Frame::~Frame() { + av_frame_free(&m_frame); +} + +Decoder::Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec) { + const AVCodecID av_codec = [&] { + switch (codec) { + case Tegra::Host1x::NvdecCommon::VideoCodec::H264: + return AV_CODEC_ID_H264; + case Tegra::Host1x::NvdecCommon::VideoCodec::VP8: + return AV_CODEC_ID_VP8; + case Tegra::Host1x::NvdecCommon::VideoCodec::VP9: + return AV_CODEC_ID_VP9; + default: + UNIMPLEMENTED_MSG("Unknown codec {}", codec); + return AV_CODEC_ID_NONE; + } + }(); + + m_codec = avcodec_find_decoder(av_codec); +} + +bool Decoder::SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceType type) const { + for (int i = 0;; i++) { + const AVCodecHWConfig* config = avcodec_get_hw_config(m_codec, i); + if (!config) { + LOG_DEBUG(HW_GPU, "{} decoder does not support device type {}", m_codec->name, + av_hwdevice_get_type_name(type)); + break; + } + if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) != 0 && + config->device_type == type) { + LOG_INFO(HW_GPU, "Using {} GPU decoder", av_hwdevice_get_type_name(type)); + *out_pix_fmt = config->pix_fmt; + return true; + } + } + + return false; +} + +std::vector<AVHWDeviceType> HardwareContext::GetSupportedDeviceTypes() { + std::vector<AVHWDeviceType> types; + AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; + + while (true) { + current_device_type = av_hwdevice_iterate_types(current_device_type); + if (current_device_type == AV_HWDEVICE_TYPE_NONE) { + return types; + } + + types.push_back(current_device_type); + } +} + +HardwareContext::~HardwareContext() { + av_buffer_unref(&m_gpu_decoder); +} + +bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context, + const Decoder& decoder) { + const auto supported_types = GetSupportedDeviceTypes(); + for (const auto type : PreferredGpuDecoders) { + AVPixelFormat hw_pix_fmt; + + if (std::ranges::find(supported_types, type) == supported_types.end()) { + LOG_DEBUG(HW_GPU, "{} explicitly unsupported", av_hwdevice_get_type_name(type)); + continue; + } + + if (!this->InitializeWithType(type)) { + continue; + } + + if (decoder.SupportsDecodingOnDevice(&hw_pix_fmt, type)) { + decoder_context.InitializeHardwareDecoder(*this, hw_pix_fmt); + return true; + } + } + + return false; +} + +bool HardwareContext::InitializeWithType(AVHWDeviceType type) { + av_buffer_unref(&m_gpu_decoder); + + if (const int ret = av_hwdevice_ctx_create(&m_gpu_decoder, type, nullptr, nullptr, 0); + ret < 0) { + LOG_DEBUG(HW_GPU, "av_hwdevice_ctx_create({}) failed: {}", av_hwdevice_get_type_name(type), + AVError(ret)); + return false; + } + +#ifdef LIBVA_FOUND + if (type == AV_HWDEVICE_TYPE_VAAPI) { + // We need to determine if this is an impersonated VAAPI driver. + auto* hwctx = reinterpret_cast<AVHWDeviceContext*>(m_gpu_decoder->data); + auto* vactx = static_cast<AVVAAPIDeviceContext*>(hwctx->hwctx); + const char* vendor_name = vaQueryVendorString(vactx->display); + if (strstr(vendor_name, "VDPAU backend")) { + // VDPAU impersonated VAAPI impls are super buggy, we need to skip them. + LOG_DEBUG(HW_GPU, "Skipping VDPAU impersonated VAAPI driver"); + return false; + } else { + // According to some user testing, certain VAAPI drivers (Intel?) could be buggy. + // Log the driver name just in case. + LOG_DEBUG(HW_GPU, "Using VAAPI driver: {}", vendor_name); + } + } +#endif + + return true; +} + +DecoderContext::DecoderContext(const Decoder& decoder) { + m_codec_context = avcodec_alloc_context3(decoder.GetCodec()); + av_opt_set(m_codec_context->priv_data, "tune", "zerolatency", 0); + m_codec_context->thread_count = 0; + m_codec_context->thread_type &= ~FF_THREAD_FRAME; +} + +DecoderContext::~DecoderContext() { + av_buffer_unref(&m_codec_context->hw_device_ctx); + avcodec_free_context(&m_codec_context); +} + +void DecoderContext::InitializeHardwareDecoder(const HardwareContext& context, + AVPixelFormat hw_pix_fmt) { + m_codec_context->hw_device_ctx = av_buffer_ref(context.GetBufferRef()); + m_codec_context->get_format = GetGpuFormat; + m_codec_context->pix_fmt = hw_pix_fmt; +} + +bool DecoderContext::OpenContext(const Decoder& decoder) { + if (const int ret = avcodec_open2(m_codec_context, decoder.GetCodec(), nullptr); ret < 0) { + LOG_ERROR(HW_GPU, "avcodec_open2 error: {}", AVError(ret)); + return false; + } + + if (!m_codec_context->hw_device_ctx) { + LOG_INFO(HW_GPU, "Using FFmpeg software decoding"); + } + + return true; +} + +bool DecoderContext::SendPacket(const Packet& packet) { + if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0) { + LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret)); + return false; + } + + return true; +} + +std::unique_ptr<Frame> DecoderContext::ReceiveFrame(bool* out_is_interlaced) { + auto dst_frame = std::make_unique<Frame>(); + + const auto ReceiveImpl = [&](AVFrame* frame) { + if (const int ret = avcodec_receive_frame(m_codec_context, frame); ret < 0) { + LOG_ERROR(HW_GPU, "avcodec_receive_frame error: {}", AVError(ret)); + return false; + } + + *out_is_interlaced = frame->interlaced_frame != 0; + return true; + }; + + if (m_codec_context->hw_device_ctx) { + // If we have a hardware context, make a separate frame here to receive the + // hardware result before sending it to the output. + Frame intermediate_frame; + + if (!ReceiveImpl(intermediate_frame.GetFrame())) { + return {}; + } + + dst_frame->SetFormat(PreferredGpuFormat); + if (const int ret = + av_hwframe_transfer_data(dst_frame->GetFrame(), intermediate_frame.GetFrame(), 0); + ret < 0) { + LOG_ERROR(HW_GPU, "av_hwframe_transfer_data error: {}", AVError(ret)); + return {}; + } + } else { + // Otherwise, decode the frame as normal. + if (!ReceiveImpl(dst_frame->GetFrame())) { + return {}; + } + } + + return dst_frame; +} + +DeinterlaceFilter::DeinterlaceFilter(const Frame& frame) { + const AVFilter* buffer_src = avfilter_get_by_name("buffer"); + const AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); + AVFilterInOut* inputs = avfilter_inout_alloc(); + AVFilterInOut* outputs = avfilter_inout_alloc(); + SCOPE_EXIT({ + avfilter_inout_free(&inputs); + avfilter_inout_free(&outputs); + }); + + // Don't know how to get the accurate time_base but it doesn't matter for yadif filter + // so just use 1/1 to make buffer filter happy + std::string args = fmt::format("video_size={}x{}:pix_fmt={}:time_base=1/1", frame.GetWidth(), + frame.GetHeight(), static_cast<int>(frame.GetPixelFormat())); + + m_filter_graph = avfilter_graph_alloc(); + int ret = avfilter_graph_create_filter(&m_source_context, buffer_src, "in", args.c_str(), + nullptr, m_filter_graph); + if (ret < 0) { + LOG_ERROR(HW_GPU, "avfilter_graph_create_filter source error: {}", AVError(ret)); + return; + } + + ret = avfilter_graph_create_filter(&m_sink_context, buffer_sink, "out", nullptr, nullptr, + m_filter_graph); + if (ret < 0) { + LOG_ERROR(HW_GPU, "avfilter_graph_create_filter sink error: {}", AVError(ret)); + return; + } + + inputs->name = av_strdup("out"); + inputs->filter_ctx = m_sink_context; + inputs->pad_idx = 0; + inputs->next = nullptr; + + outputs->name = av_strdup("in"); + outputs->filter_ctx = m_source_context; + outputs->pad_idx = 0; + outputs->next = nullptr; + + const char* description = "yadif=1:-1:0"; + ret = avfilter_graph_parse_ptr(m_filter_graph, description, &inputs, &outputs, nullptr); + if (ret < 0) { + LOG_ERROR(HW_GPU, "avfilter_graph_parse_ptr error: {}", AVError(ret)); + return; + } + + ret = avfilter_graph_config(m_filter_graph, nullptr); + if (ret < 0) { + LOG_ERROR(HW_GPU, "avfilter_graph_config error: {}", AVError(ret)); + return; + } + + m_initialized = true; +} + +bool DeinterlaceFilter::AddSourceFrame(const Frame& frame) { + if (const int ret = av_buffersrc_add_frame_flags(m_source_context, frame.GetFrame(), + AV_BUFFERSRC_FLAG_KEEP_REF); + ret < 0) { + LOG_ERROR(HW_GPU, "av_buffersrc_add_frame_flags error: {}", AVError(ret)); + return false; + } + + return true; +} + +std::unique_ptr<Frame> DeinterlaceFilter::DrainSinkFrame() { + auto dst_frame = std::make_unique<Frame>(); + const int ret = av_buffersink_get_frame(m_sink_context, dst_frame->GetFrame()); + + if (ret == AVERROR(EAGAIN) || ret == AVERROR(AVERROR_EOF)) { + return {}; + } + + if (ret < 0) { + LOG_ERROR(HW_GPU, "av_buffersink_get_frame error: {}", AVError(ret)); + return {}; + } + + return dst_frame; +} + +DeinterlaceFilter::~DeinterlaceFilter() { + avfilter_graph_free(&m_filter_graph); +} + +void DecodeApi::Reset() { + m_deinterlace_filter.reset(); + m_hardware_context.reset(); + m_decoder_context.reset(); + m_decoder.reset(); +} + +bool DecodeApi::Initialize(Tegra::Host1x::NvdecCommon::VideoCodec codec) { + this->Reset(); + m_decoder.emplace(codec); + m_decoder_context.emplace(*m_decoder); + + // Enable GPU decoding if requested. + if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) { + m_hardware_context.emplace(); + m_hardware_context->InitializeForDecoder(*m_decoder_context, *m_decoder); + } + + // Open the decoder context. + if (!m_decoder_context->OpenContext(*m_decoder)) { + this->Reset(); + return false; + } + + return true; +} + +bool DecodeApi::SendPacket(std::span<const u8> packet_data, size_t configuration_size) { + FFmpeg::Packet packet(packet_data); + return m_decoder_context->SendPacket(packet); +} + +void DecodeApi::ReceiveFrames(std::queue<std::unique_ptr<Frame>>& frame_queue) { + // Receive raw frame from decoder. + bool is_interlaced; + auto frame = m_decoder_context->ReceiveFrame(&is_interlaced); + if (!frame) { + return; + } + + if (!is_interlaced) { + // If the frame is not interlaced, we can pend it now. + frame_queue.push(std::move(frame)); + } else { + // Create the deinterlacer if needed. + if (!m_deinterlace_filter) { + m_deinterlace_filter.emplace(*frame); + } + + // Add the frame we just received. + if (!m_deinterlace_filter->AddSourceFrame(*frame)) { + return; + } + + // Pend output fields. + while (true) { + auto filter_frame = m_deinterlace_filter->DrainSinkFrame(); + if (!filter_frame) { + break; + } + + frame_queue.push(std::move(filter_frame)); + } + } +} + +} // namespace FFmpeg diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.h b/src/video_core/host1x/ffmpeg/ffmpeg.h new file mode 100644 index 000000000..1de0bbd83 --- /dev/null +++ b/src/video_core/host1x/ffmpeg/ffmpeg.h @@ -0,0 +1,213 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <memory> +#include <optional> +#include <span> +#include <vector> +#include <queue> + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "video_core/host1x/nvdec_common.h" + +extern "C" { +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#endif + +#include <libavcodec/avcodec.h> +#include <libavfilter/avfilter.h> +#include <libavfilter/buffersink.h> +#include <libavfilter/buffersrc.h> +#include <libavutil/avutil.h> +#include <libavutil/opt.h> + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif +} + +namespace FFmpeg { + +class Packet; +class Frame; +class Decoder; +class HardwareContext; +class DecoderContext; +class DeinterlaceFilter; + +// Wraps an AVPacket, a container for compressed bitstream data. +class Packet { +public: + YUZU_NON_COPYABLE(Packet); + YUZU_NON_MOVEABLE(Packet); + + explicit Packet(std::span<const u8> data); + ~Packet(); + + AVPacket* GetPacket() const { + return m_packet; + } + +private: + AVPacket* m_packet{}; +}; + +// Wraps an AVFrame, a container for audio and video stream data. +class Frame { +public: + YUZU_NON_COPYABLE(Frame); + YUZU_NON_MOVEABLE(Frame); + + explicit Frame(); + ~Frame(); + + int GetWidth() const { + return m_frame->width; + } + + int GetHeight() const { + return m_frame->height; + } + + AVPixelFormat GetPixelFormat() const { + return static_cast<AVPixelFormat>(m_frame->format); + } + + int GetStride(int plane) const { + return m_frame->linesize[plane]; + } + + int* GetStrides() const { + return m_frame->linesize; + } + + u8* GetData(int plane) const { + return m_frame->data[plane]; + } + + u8** GetPlanes() const { + return m_frame->data; + } + + void SetFormat(int format) { + m_frame->format = format; + } + + AVFrame* GetFrame() const { + return m_frame; + } + +private: + AVFrame* m_frame{}; +}; + +// Wraps an AVCodec, a type containing information about a codec. +class Decoder { +public: + YUZU_NON_COPYABLE(Decoder); + YUZU_NON_MOVEABLE(Decoder); + + explicit Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec); + ~Decoder() = default; + + bool SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceType type) const; + + const AVCodec* GetCodec() const { + return m_codec; + } + +private: + const AVCodec* m_codec{}; +}; + +// Wraps AVBufferRef for an accelerated decoder. +class HardwareContext { +public: + YUZU_NON_COPYABLE(HardwareContext); + YUZU_NON_MOVEABLE(HardwareContext); + + static std::vector<AVHWDeviceType> GetSupportedDeviceTypes(); + + explicit HardwareContext() = default; + ~HardwareContext(); + + bool InitializeForDecoder(DecoderContext& decoder_context, const Decoder& decoder); + + AVBufferRef* GetBufferRef() const { + return m_gpu_decoder; + } + +private: + bool InitializeWithType(AVHWDeviceType type); + + AVBufferRef* m_gpu_decoder{}; +}; + +// Wraps an AVCodecContext. +class DecoderContext { +public: + YUZU_NON_COPYABLE(DecoderContext); + YUZU_NON_MOVEABLE(DecoderContext); + + explicit DecoderContext(const Decoder& decoder); + ~DecoderContext(); + + void InitializeHardwareDecoder(const HardwareContext& context, AVPixelFormat hw_pix_fmt); + bool OpenContext(const Decoder& decoder); + bool SendPacket(const Packet& packet); + std::unique_ptr<Frame> ReceiveFrame(bool* out_is_interlaced); + + AVCodecContext* GetCodecContext() const { + return m_codec_context; + } + +private: + AVCodecContext* m_codec_context{}; +}; + +// Wraps an AVFilterGraph. +class DeinterlaceFilter { +public: + YUZU_NON_COPYABLE(DeinterlaceFilter); + YUZU_NON_MOVEABLE(DeinterlaceFilter); + + explicit DeinterlaceFilter(const Frame& frame); + ~DeinterlaceFilter(); + + bool AddSourceFrame(const Frame& frame); + std::unique_ptr<Frame> DrainSinkFrame(); + +private: + AVFilterGraph* m_filter_graph{}; + AVFilterContext* m_source_context{}; + AVFilterContext* m_sink_context{}; + bool m_initialized{}; +}; + +class DecodeApi { +public: + YUZU_NON_COPYABLE(DecodeApi); + YUZU_NON_MOVEABLE(DecodeApi); + + DecodeApi() = default; + ~DecodeApi() = default; + + bool Initialize(Tegra::Host1x::NvdecCommon::VideoCodec codec); + void Reset(); + + bool SendPacket(std::span<const u8> packet_data, size_t configuration_size); + void ReceiveFrames(std::queue<std::unique_ptr<Frame>>& frame_queue); + +private: + std::optional<FFmpeg::Decoder> m_decoder; + std::optional<FFmpeg::DecoderContext> m_decoder_context; + std::optional<FFmpeg::HardwareContext> m_hardware_context; + std::optional<FFmpeg::DeinterlaceFilter> m_deinterlace_filter; +}; + +} // namespace FFmpeg diff --git a/src/video_core/host1x/nvdec.cpp b/src/video_core/host1x/nvdec.cpp index a4bd5b79f..b8f5866d3 100644 --- a/src/video_core/host1x/nvdec.cpp +++ b/src/video_core/host1x/nvdec.cpp @@ -28,7 +28,7 @@ void Nvdec::ProcessMethod(u32 method, u32 argument) { } } -AVFramePtr Nvdec::GetFrame() { +std::unique_ptr<FFmpeg::Frame> Nvdec::GetFrame() { return codec->GetCurrentFrame(); } diff --git a/src/video_core/host1x/nvdec.h b/src/video_core/host1x/nvdec.h index 3949d5181..ddddb8d28 100644 --- a/src/video_core/host1x/nvdec.h +++ b/src/video_core/host1x/nvdec.h @@ -23,7 +23,7 @@ public: void ProcessMethod(u32 method, u32 argument); /// Return most recently decoded frame - [[nodiscard]] AVFramePtr GetFrame(); + [[nodiscard]] std::unique_ptr<FFmpeg::Frame> GetFrame(); private: /// Invoke codec to decode a frame diff --git a/src/video_core/host1x/vic.cpp b/src/video_core/host1x/vic.cpp index 10d7ef884..2a5eba415 100644 --- a/src/video_core/host1x/vic.cpp +++ b/src/video_core/host1x/vic.cpp @@ -82,27 +82,26 @@ void Vic::Execute() { return; } const VicConfig config{host1x.MemoryManager().Read<u64>(config_struct_address + 0x20)}; - const AVFramePtr frame_ptr = nvdec_processor->GetFrame(); - const auto* frame = frame_ptr.get(); + auto frame = nvdec_processor->GetFrame(); if (!frame) { return; } const u64 surface_width = config.surface_width_minus1 + 1; const u64 surface_height = config.surface_height_minus1 + 1; - if (static_cast<u64>(frame->width) != surface_width || - static_cast<u64>(frame->height) != surface_height) { + if (static_cast<u64>(frame->GetWidth()) != surface_width || + static_cast<u64>(frame->GetHeight()) != surface_height) { // TODO: Properly support multiple video streams with differing frame dimensions LOG_WARNING(Service_NVDRV, "Frame dimensions {}x{} don't match surface dimensions {}x{}", - frame->width, frame->height, surface_width, surface_height); + frame->GetWidth(), frame->GetHeight(), surface_width, surface_height); } switch (config.pixel_format) { case VideoPixelFormat::RGBA8: case VideoPixelFormat::BGRA8: case VideoPixelFormat::RGBX8: - WriteRGBFrame(frame, config); + WriteRGBFrame(std::move(frame), config); break; case VideoPixelFormat::YUV420: - WriteYUVFrame(frame, config); + WriteYUVFrame(std::move(frame), config); break; default: UNIMPLEMENTED_MSG("Unknown video pixel format {:X}", config.pixel_format.Value()); @@ -110,10 +109,14 @@ void Vic::Execute() { } } -void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) { +void Vic::WriteRGBFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& config) { LOG_TRACE(Service_NVDRV, "Writing RGB Frame"); - if (!scaler_ctx || frame->width != scaler_width || frame->height != scaler_height) { + const auto frame_width = frame->GetWidth(); + const auto frame_height = frame->GetHeight(); + const auto frame_format = frame->GetPixelFormat(); + + if (!scaler_ctx || frame_width != scaler_width || frame_height != scaler_height) { const AVPixelFormat target_format = [pixel_format = config.pixel_format]() { switch (pixel_format) { case VideoPixelFormat::RGBA8: @@ -129,27 +132,26 @@ void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) { sws_freeContext(scaler_ctx); // Frames are decoded into either YUV420 or NV12 formats. Convert to desired RGB format - scaler_ctx = sws_getContext(frame->width, frame->height, - static_cast<AVPixelFormat>(frame->format), frame->width, - frame->height, target_format, 0, nullptr, nullptr, nullptr); - scaler_width = frame->width; - scaler_height = frame->height; + scaler_ctx = sws_getContext(frame_width, frame_height, frame_format, frame_width, + frame_height, target_format, 0, nullptr, nullptr, nullptr); + scaler_width = frame_width; + scaler_height = frame_height; converted_frame_buffer.reset(); } if (!converted_frame_buffer) { - const size_t frame_size = frame->width * frame->height * 4; + const size_t frame_size = frame_width * frame_height * 4; converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(frame_size)), av_free}; } - const std::array<int, 4> converted_stride{frame->width * 4, frame->height * 4, 0, 0}; + const std::array<int, 4> converted_stride{frame_width * 4, frame_height * 4, 0, 0}; u8* const converted_frame_buf_addr{converted_frame_buffer.get()}; - sws_scale(scaler_ctx, frame->data, frame->linesize, 0, frame->height, &converted_frame_buf_addr, - converted_stride.data()); + sws_scale(scaler_ctx, frame->GetPlanes(), frame->GetStrides(), 0, frame_height, + &converted_frame_buf_addr, converted_stride.data()); // Use the minimum of surface/frame dimensions to avoid buffer overflow. const u32 surface_width = static_cast<u32>(config.surface_width_minus1) + 1; const u32 surface_height = static_cast<u32>(config.surface_height_minus1) + 1; - const u32 width = std::min(surface_width, static_cast<u32>(frame->width)); - const u32 height = std::min(surface_height, static_cast<u32>(frame->height)); + const u32 width = std::min(surface_width, static_cast<u32>(frame_width)); + const u32 height = std::min(surface_height, static_cast<u32>(frame_height)); const u32 blk_kind = static_cast<u32>(config.block_linear_kind); if (blk_kind != 0) { // swizzle pitch linear to block linear @@ -169,23 +171,23 @@ void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) { } } -void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) { +void Vic::WriteYUVFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& config) { LOG_TRACE(Service_NVDRV, "Writing YUV420 Frame"); const std::size_t surface_width = config.surface_width_minus1 + 1; const std::size_t surface_height = config.surface_height_minus1 + 1; const std::size_t aligned_width = (surface_width + 0xff) & ~0xffUL; // Use the minimum of surface/frame dimensions to avoid buffer overflow. - const auto frame_width = std::min(surface_width, static_cast<size_t>(frame->width)); - const auto frame_height = std::min(surface_height, static_cast<size_t>(frame->height)); + const auto frame_width = std::min(surface_width, static_cast<size_t>(frame->GetWidth())); + const auto frame_height = std::min(surface_height, static_cast<size_t>(frame->GetHeight())); - const auto stride = static_cast<size_t>(frame->linesize[0]); + const auto stride = static_cast<size_t>(frame->GetStride(0)); luma_buffer.resize_destructive(aligned_width * surface_height); chroma_buffer.resize_destructive(aligned_width * surface_height / 2); // Populate luma buffer - const u8* luma_src = frame->data[0]; + const u8* luma_src = frame->GetData(0); for (std::size_t y = 0; y < frame_height; ++y) { const std::size_t src = y * stride; const std::size_t dst = y * aligned_width; @@ -196,16 +198,16 @@ void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) { // Chroma const std::size_t half_height = frame_height / 2; - const auto half_stride = static_cast<size_t>(frame->linesize[1]); + const auto half_stride = static_cast<size_t>(frame->GetStride(1)); - switch (frame->format) { + switch (frame->GetPixelFormat()) { case AV_PIX_FMT_YUV420P: { // Frame from FFmpeg software // Populate chroma buffer from both channels with interleaving. const std::size_t half_width = frame_width / 2; u8* chroma_buffer_data = chroma_buffer.data(); - const u8* chroma_b_src = frame->data[1]; - const u8* chroma_r_src = frame->data[2]; + const u8* chroma_b_src = frame->GetData(1); + const u8* chroma_r_src = frame->GetData(2); for (std::size_t y = 0; y < half_height; ++y) { const std::size_t src = y * half_stride; const std::size_t dst = y * aligned_width; @@ -219,7 +221,7 @@ void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) { case AV_PIX_FMT_NV12: { // Frame from VA-API hardware // This is already interleaved so just copy - const u8* chroma_src = frame->data[1]; + const u8* chroma_src = frame->GetData(1); for (std::size_t y = 0; y < half_height; ++y) { const std::size_t src = y * stride; const std::size_t dst = y * aligned_width; diff --git a/src/video_core/host1x/vic.h b/src/video_core/host1x/vic.h index 3d9753047..6c868f062 100644 --- a/src/video_core/host1x/vic.h +++ b/src/video_core/host1x/vic.h @@ -39,9 +39,9 @@ public: private: void Execute(); - void WriteRGBFrame(const AVFrame* frame, const VicConfig& config); + void WriteRGBFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& config); - void WriteYUVFrame(const AVFrame* frame, const VicConfig& config); + void WriteYUVFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& config); Host1x& host1x; std::shared_ptr<Tegra::Host1x::Nvdec> nvdec_processor; diff --git a/src/video_core/query_cache/query_cache.h b/src/video_core/query_cache/query_cache.h index 78b42b518..efa9adf7a 100644 --- a/src/video_core/query_cache/query_cache.h +++ b/src/video_core/query_cache/query_cache.h @@ -266,7 +266,7 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type return; } if (False(query_base->flags & QueryFlagBits::IsFinalValueSynced)) [[unlikely]] { - UNREACHABLE(); + ASSERT(false); return; } query_base->value += streamer->GetAmmendValue(); diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 33e1fb663..90278052a 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -38,8 +38,6 @@ add_executable(yuzu compatdb.ui compatibility_list.cpp compatibility_list.h - configuration/config.cpp - configuration/config.h configuration/configuration_shared.cpp configuration/configuration_shared.h configuration/configure.ui @@ -147,6 +145,8 @@ add_executable(yuzu configuration/shared_translation.h configuration/shared_widget.cpp configuration/shared_widget.h + configuration/qt_config.cpp + configuration/qt_config.h debugger/console.cpp debugger/console.h debugger/controller.cpp @@ -252,6 +252,7 @@ file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*) if (ENABLE_QT_TRANSLATION) set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend") option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF) + option(WORKAROUND_BROKEN_LUPDATE "Run lupdate directly through CMake if Qt's convenience wrappers don't work" OFF) # Update source TS file if enabled if (GENERATE_QT_TRANSLATION) @@ -259,19 +260,51 @@ if (ENABLE_QT_TRANSLATION) # these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals # so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations") - qt_create_translation(QM_FILES - ${SRCS} - ${UIS} - ${YUZU_QT_LANGUAGES}/en.ts - OPTIONS - -source-language en_US - -target-language en_US - ) + if (WORKAROUND_BROKEN_LUPDATE) + add_custom_command(OUTPUT ${YUZU_QT_LANGUAGES}/en.ts + COMMAND lupdate + -source-language en_US + -target-language en_US + ${SRCS} + ${UIS} + -ts ${YUZU_QT_LANGUAGES}/en.ts + DEPENDS + ${SRCS} + ${UIS} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + ) + else() + qt_create_translation(QM_FILES + ${SRCS} + ${UIS} + ${YUZU_QT_LANGUAGES}/en.ts + OPTIONS + -source-language en_US + -target-language en_US + ) + endif() # Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts) set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals") - qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US) + if (WORKAROUND_BROKEN_LUPDATE) + add_custom_command(OUTPUT ${GENERATED_PLURALS_FILE} + COMMAND lupdate + -source-language en_US + -target-language en_US + ${SRCS} + ${UIS} + -ts ${GENERATED_PLURALS_FILE} + DEPENDS + ${SRCS} + ${UIS} + WORKING_DIRECTORY + ${CMAKE_CURRENT_SOURCE_DIR} + ) + else() + qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US) + endif() add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE}) endif() @@ -344,7 +377,7 @@ endif() create_target_directory_groups(yuzu) -target_link_libraries(yuzu PRIVATE common core input_common network video_core) +target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core) target_link_libraries(yuzu PRIVATE Boost::headers glad Qt${QT_MAJOR_VERSION}::Widgets) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp deleted file mode 100644 index c0ae6468b..000000000 --- a/src/yuzu/configuration/config.cpp +++ /dev/null @@ -1,1309 +0,0 @@ -// SPDX-FileCopyrightText: 2014 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <algorithm> -#include <array> -#include <QKeySequence> -#include <QSettings> -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "common/settings.h" -#include "common/settings_common.h" -#include "common/settings_enums.h" -#include "core/core.h" -#include "core/hle/service/acc/profile_manager.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "input_common/main.h" -#include "network/network.h" -#include "yuzu/configuration/config.h" - -namespace FS = Common::FS; - -Config::Config(const std::string& config_name, ConfigType config_type) - : type(config_type), global{config_type == ConfigType::GlobalConfig} { - Initialize(config_name); -} - -Config::~Config() { - if (global) { - Save(); - } -} - -const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { - Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F, - Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T, - Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, - Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0, - Qt::Key_Q, Qt::Key_E, -}; - -const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = { - Qt::Key_7, - Qt::Key_8, -}; - -const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ - { - Qt::Key_W, - Qt::Key_S, - Qt::Key_A, - Qt::Key_D, - }, - { - Qt::Key_I, - Qt::Key_K, - Qt::Key_J, - Qt::Key_L, - }, -}}; - -const std::array<int, 2> Config::default_stick_mod = { - Qt::Key_Shift, - 0, -}; - -const std::array<int, 2> Config::default_ringcon_analogs{{ - Qt::Key_A, - Qt::Key_D, -}}; - -const std::map<Settings::AntiAliasing, QString> Config::anti_aliasing_texts_map = { - {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, - {Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))}, - {Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))}, -}; - -const std::map<Settings::ScalingFilter, QString> Config::scaling_filter_texts_map = { - {Settings::ScalingFilter::NearestNeighbor, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))}, - {Settings::ScalingFilter::Bilinear, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))}, - {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))}, - {Settings::ScalingFilter::Gaussian, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))}, - {Settings::ScalingFilter::ScaleForce, - QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))}, - {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, -}; - -const std::map<Settings::ConsoleMode, QString> Config::use_docked_mode_texts_map = { - {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, - {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, -}; - -const std::map<Settings::GpuAccuracy, QString> Config::gpu_accuracy_texts_map = { - {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))}, - {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))}, - {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))}, -}; - -const std::map<Settings::RendererBackend, QString> Config::renderer_backend_texts_map = { - {Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))}, - {Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))}, - {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))}, -}; - -const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_map = { - {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))}, - {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))}, - {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))}, -}; - -// This shouldn't have anything except static initializers (no functions). So -// QKeySequence(...).toString() is NOT ALLOWED HERE. -// 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. -// clang-format off -const std::array<UISettings::Shortcut, 23> Config::default_hotkeys{{ - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral("R+Plus+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral("L+Plus+Minus"), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral(""), QStringLiteral(""), Qt::ApplicationShortcut, false}}, - {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}}, -}}; -// clang-format on - -void Config::Initialize(const std::string& config_name) { - const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); - const auto config_file = fmt::format("{}.ini", config_name); - - switch (type) { - case ConfigType::GlobalConfig: - qt_config_loc = FS::PathToUTF8String(fs_config_loc / config_file); - void(FS::CreateParentDir(qt_config_loc)); - qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), - QSettings::IniFormat); - Reload(); - break; - case ConfigType::PerGameConfig: - qt_config_loc = - FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); - void(FS::CreateParentDir(qt_config_loc)); - qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), - QSettings::IniFormat); - Reload(); - break; - case ConfigType::InputProfile: - qt_config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); - void(FS::CreateParentDir(qt_config_loc)); - qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), - QSettings::IniFormat); - break; - } -} - -bool Config::IsCustomConfig() { - return type == ConfigType::PerGameConfig; -} - -void Config::ReadPlayerValue(std::size_t player_index) { - const QString player_prefix = [this, player_index] { - if (type == ConfigType::InputProfile) { - return QString{}; - } else { - return QStringLiteral("player_%1_").arg(player_index); - } - }(); - - auto& player = Settings::values.players.GetValue()[player_index]; - if (IsCustomConfig()) { - const auto profile_name = - qt_config->value(QStringLiteral("%1profile_name").arg(player_prefix), QString{}) - .toString() - .toStdString(); - if (profile_name.empty()) { - // Use the global input config - player = Settings::values.players.GetValue(true)[player_index]; - return; - } - player.profile_name = profile_name; - } - - if (player_prefix.isEmpty() && Settings::IsConfiguringGlobal()) { - const auto controller = static_cast<Settings::ControllerType>( - qt_config - ->value(QStringLiteral("%1type").arg(player_prefix), - static_cast<u8>(Settings::ControllerType::ProController)) - .toUInt()); - - if (controller == Settings::ControllerType::LeftJoycon || - controller == Settings::ControllerType::RightJoycon) { - player.controller_type = controller; - } - } else { - player.connected = - ReadSetting(QStringLiteral("%1connected").arg(player_prefix), player_index == 0) - .toBool(); - - player.controller_type = static_cast<Settings::ControllerType>( - qt_config - ->value(QStringLiteral("%1type").arg(player_prefix), - static_cast<u8>(Settings::ControllerType::ProController)) - .toUInt()); - - player.vibration_enabled = - qt_config->value(QStringLiteral("%1vibration_enabled").arg(player_prefix), true) - .toBool(); - - player.vibration_strength = - qt_config->value(QStringLiteral("%1vibration_strength").arg(player_prefix), 100) - .toInt(); - - player.body_color_left = qt_config - ->value(QStringLiteral("%1body_color_left").arg(player_prefix), - Settings::JOYCON_BODY_NEON_BLUE) - .toUInt(); - player.body_color_right = - qt_config - ->value(QStringLiteral("%1body_color_right").arg(player_prefix), - Settings::JOYCON_BODY_NEON_RED) - .toUInt(); - player.button_color_left = - qt_config - ->value(QStringLiteral("%1button_color_left").arg(player_prefix), - Settings::JOYCON_BUTTONS_NEON_BLUE) - .toUInt(); - player.button_color_right = - qt_config - ->value(QStringLiteral("%1button_color_right").arg(player_prefix), - Settings::JOYCON_BUTTONS_NEON_RED) - .toUInt(); - } - - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - auto& player_buttons = player.buttons[i]; - - player_buttons = qt_config - ->value(QStringLiteral("%1").arg(player_prefix) + - QString::fromUtf8(Settings::NativeButton::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (player_buttons.empty()) { - player_buttons = default_param; - } - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_stick_mod[i], 0.5f); - auto& player_analogs = player.analogs[i]; - - player_analogs = qt_config - ->value(QStringLiteral("%1").arg(player_prefix) + - QString::fromUtf8(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (player_analogs.empty()) { - player_analogs = default_param; - } - } - - for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); - auto& player_motions = player.motions[i]; - - player_motions = qt_config - ->value(QStringLiteral("%1").arg(player_prefix) + - QString::fromUtf8(Settings::NativeMotion::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (player_motions.empty()) { - player_motions = default_param; - } - } -} - -void Config::ReadDebugValues() { - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; - - debug_pad_buttons = qt_config - ->value(QStringLiteral("debug_pad_") + - QString::fromUtf8(Settings::NativeButton::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (debug_pad_buttons.empty()) { - debug_pad_buttons = default_param; - } - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_stick_mod[i], 0.5f); - auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; - - debug_pad_analogs = qt_config - ->value(QStringLiteral("debug_pad_") + - QString::fromUtf8(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (debug_pad_analogs.empty()) { - debug_pad_analogs = default_param; - } - } -} - -void Config::ReadTouchscreenValues() { - Settings::values.touchscreen.enabled = - ReadSetting(QStringLiteral("touchscreen_enabled"), true).toBool(); - - Settings::values.touchscreen.rotation_angle = - ReadSetting(QStringLiteral("touchscreen_angle"), 0).toUInt(); - Settings::values.touchscreen.diameter_x = - ReadSetting(QStringLiteral("touchscreen_diameter_x"), 15).toUInt(); - Settings::values.touchscreen.diameter_y = - ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt(); -} - -void Config::ReadHidbusValues() { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); - auto& ringcon_analogs = Settings::values.ringcon_analogs; - - ringcon_analogs = - qt_config->value(QStringLiteral("ring_controller"), QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (ringcon_analogs.empty()) { - ringcon_analogs = default_param; - } -} - -void Config::ReadAudioValues() { - qt_config->beginGroup(QStringLiteral("Audio")); - - ReadCategory(Settings::Category::Audio); - ReadCategory(Settings::Category::UiAudio); - - qt_config->endGroup(); -} - -void Config::ReadControlValues() { - qt_config->beginGroup(QStringLiteral("Controls")); - - ReadCategory(Settings::Category::Controls); - - Settings::values.players.SetGlobal(!IsCustomConfig()); - for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { - ReadPlayerValue(p); - } - - // Disable docked mode if handheld is selected - const auto controller_type = Settings::values.players.GetValue()[0].controller_type; - if (controller_type == Settings::ControllerType::Handheld) { - Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig()); - Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); - } - - if (IsCustomConfig()) { - qt_config->endGroup(); - return; - } - ReadDebugValues(); - ReadTouchscreenValues(); - ReadMotionTouchValues(); - ReadHidbusValues(); - - qt_config->endGroup(); -} - -void Config::ReadMotionTouchValues() { - int num_touch_from_button_maps = - qt_config->beginReadArray(QStringLiteral("touch_from_button_maps")); - - if (num_touch_from_button_maps > 0) { - const auto append_touch_from_button_map = [this] { - Settings::TouchFromButtonMap map; - map.name = ReadSetting(QStringLiteral("name"), QStringLiteral("default")) - .toString() - .toStdString(); - const int num_touch_maps = qt_config->beginReadArray(QStringLiteral("entries")); - map.buttons.reserve(num_touch_maps); - for (int i = 0; i < num_touch_maps; i++) { - qt_config->setArrayIndex(i); - std::string touch_mapping = - ReadSetting(QStringLiteral("bind")).toString().toStdString(); - map.buttons.emplace_back(std::move(touch_mapping)); - } - qt_config->endArray(); // entries - Settings::values.touch_from_button_maps.emplace_back(std::move(map)); - }; - - for (int i = 0; i < num_touch_from_button_maps; ++i) { - qt_config->setArrayIndex(i); - append_touch_from_button_map(); - } - } else { - Settings::values.touch_from_button_maps.emplace_back( - Settings::TouchFromButtonMap{"default", {}}); - num_touch_from_button_maps = 1; - } - qt_config->endArray(); - - Settings::values.touch_from_button_map_index = std::clamp( - Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); -} - -void Config::ReadCoreValues() { - qt_config->beginGroup(QStringLiteral("Core")); - - ReadCategory(Settings::Category::Core); - - qt_config->endGroup(); -} - -void Config::ReadDataStorageValues() { - qt_config->beginGroup(QStringLiteral("Data Storage")); - - FS::SetYuzuPath( - FS::YuzuPath::NANDDir, - qt_config - ->value(QStringLiteral("nand_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))) - .toString() - .toStdString()); - FS::SetYuzuPath( - FS::YuzuPath::SDMCDir, - qt_config - ->value(QStringLiteral("sdmc_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))) - .toString() - .toStdString()); - FS::SetYuzuPath( - FS::YuzuPath::LoadDir, - qt_config - ->value(QStringLiteral("load_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))) - .toString() - .toStdString()); - FS::SetYuzuPath( - FS::YuzuPath::DumpDir, - qt_config - ->value(QStringLiteral("dump_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))) - .toString() - .toStdString()); - FS::SetYuzuPath(FS::YuzuPath::TASDir, - qt_config - ->value(QStringLiteral("tas_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir))) - .toString() - .toStdString()); - - ReadCategory(Settings::Category::DataStorage); - - qt_config->endGroup(); -} - -void Config::ReadDebuggingValues() { - qt_config->beginGroup(QStringLiteral("Debugging")); - - // Intentionally not using the QT default setting as this is intended to be changed in the ini - Settings::values.record_frame_times = - qt_config->value(QStringLiteral("record_frame_times"), false).toBool(); - - ReadCategory(Settings::Category::Debugging); - ReadCategory(Settings::Category::DebuggingGraphics); - - qt_config->endGroup(); -} - -void Config::ReadServiceValues() { - qt_config->beginGroup(QStringLiteral("Services")); - - ReadCategory(Settings::Category::Services); - - qt_config->endGroup(); -} - -void Config::ReadDisabledAddOnValues() { - const auto size = qt_config->beginReadArray(QStringLiteral("DisabledAddOns")); - - for (int i = 0; i < size; ++i) { - qt_config->setArrayIndex(i); - const auto title_id = ReadSetting(QStringLiteral("title_id"), 0).toULongLong(); - std::vector<std::string> out; - const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled")); - for (int j = 0; j < d_size; ++j) { - qt_config->setArrayIndex(j); - out.push_back(ReadSetting(QStringLiteral("d"), QString{}).toString().toStdString()); - } - qt_config->endArray(); - Settings::values.disabled_addons.insert_or_assign(title_id, out); - } - - qt_config->endArray(); -} - -void Config::ReadMiscellaneousValues() { - qt_config->beginGroup(QStringLiteral("Miscellaneous")); - - ReadCategory(Settings::Category::Miscellaneous); - - qt_config->endGroup(); -} - -void Config::ReadPathValues() { - qt_config->beginGroup(QStringLiteral("Paths")); - - UISettings::values.roms_path = ReadSetting(QStringLiteral("romsPath")).toString(); - UISettings::values.symbols_path = ReadSetting(QStringLiteral("symbolsPath")).toString(); - UISettings::values.game_dir_deprecated = - ReadSetting(QStringLiteral("gameListRootDir"), QStringLiteral(".")).toString(); - UISettings::values.game_dir_deprecated_deepscan = - ReadSetting(QStringLiteral("gameListDeepScan"), false).toBool(); - const int gamedirs_size = qt_config->beginReadArray(QStringLiteral("gamedirs")); - for (int i = 0; i < gamedirs_size; ++i) { - qt_config->setArrayIndex(i); - UISettings::GameDir game_dir; - game_dir.path = ReadSetting(QStringLiteral("path")).toString(); - game_dir.deep_scan = ReadSetting(QStringLiteral("deep_scan"), false).toBool(); - game_dir.expanded = ReadSetting(QStringLiteral("expanded"), true).toBool(); - UISettings::values.game_dirs.append(game_dir); - } - qt_config->endArray(); - // create NAND and SD card directories if empty, these are not removable through the UI, - // also carries over old game list settings if present - if (UISettings::values.game_dirs.isEmpty()) { - UISettings::GameDir game_dir; - game_dir.path = QStringLiteral("SDMC"); - game_dir.expanded = true; - UISettings::values.game_dirs.append(game_dir); - game_dir.path = QStringLiteral("UserNAND"); - UISettings::values.game_dirs.append(game_dir); - game_dir.path = QStringLiteral("SysNAND"); - UISettings::values.game_dirs.append(game_dir); - if (UISettings::values.game_dir_deprecated != QStringLiteral(".")) { - game_dir.path = UISettings::values.game_dir_deprecated; - game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan; - UISettings::values.game_dirs.append(game_dir); - } - } - UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList(); - UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString(); - - qt_config->endGroup(); -} - -void Config::ReadCpuValues() { - qt_config->beginGroup(QStringLiteral("Cpu")); - - ReadCategory(Settings::Category::Cpu); - ReadCategory(Settings::Category::CpuDebug); - ReadCategory(Settings::Category::CpuUnsafe); - - qt_config->endGroup(); -} - -void Config::ReadRendererValues() { - qt_config->beginGroup(QStringLiteral("Renderer")); - - ReadCategory(Settings::Category::Renderer); - ReadCategory(Settings::Category::RendererAdvanced); - ReadCategory(Settings::Category::RendererDebug); - - qt_config->endGroup(); -} - -void Config::ReadScreenshotValues() { - qt_config->beginGroup(QStringLiteral("Screenshots")); - - ReadCategory(Settings::Category::Screenshots); - FS::SetYuzuPath( - FS::YuzuPath::ScreenshotsDir, - qt_config - ->value(QStringLiteral("screenshot_path"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir))) - .toString() - .toStdString()); - - qt_config->endGroup(); -} - -void Config::ReadShortcutValues() { - qt_config->beginGroup(QStringLiteral("Shortcuts")); - - for (const auto& [name, group, shortcut] : default_hotkeys) { - qt_config->beginGroup(group); - qt_config->beginGroup(name); - // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1 - // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open - // a file dialog in windowed mode - UISettings::values.shortcuts.push_back( - {name, - group, - {ReadSetting(QStringLiteral("KeySeq"), shortcut.keyseq).toString(), - ReadSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq) - .toString(), - shortcut.context, ReadSetting(QStringLiteral("Repeat"), shortcut.repeat).toBool()}}); - qt_config->endGroup(); - qt_config->endGroup(); - } - - qt_config->endGroup(); -} - -void Config::ReadSystemValues() { - qt_config->beginGroup(QStringLiteral("System")); - - ReadCategory(Settings::Category::System); - ReadCategory(Settings::Category::SystemAudio); - - qt_config->endGroup(); -} - -void Config::ReadUIValues() { - qt_config->beginGroup(QStringLiteral("UI")); - - UISettings::values.theme = - ReadSetting( - QStringLiteral("theme"), - QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)) - .toString(); - - ReadUIGamelistValues(); - ReadUILayoutValues(); - ReadPathValues(); - ReadScreenshotValues(); - ReadShortcutValues(); - ReadMultiplayerValues(); - - ReadCategory(Settings::Category::Ui); - ReadCategory(Settings::Category::UiGeneral); - - qt_config->endGroup(); -} - -void Config::ReadUIGamelistValues() { - qt_config->beginGroup(QStringLiteral("UIGameList")); - - ReadCategory(Settings::Category::UiGameList); - - const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites")); - for (int i = 0; i < favorites_size; i++) { - qt_config->setArrayIndex(i); - UISettings::values.favorited_ids.append( - ReadSetting(QStringLiteral("program_id")).toULongLong()); - } - qt_config->endArray(); - - qt_config->endGroup(); -} - -void Config::ReadUILayoutValues() { - qt_config->beginGroup(QStringLiteral("UILayout")); - - UISettings::values.geometry = ReadSetting(QStringLiteral("geometry")).toByteArray(); - UISettings::values.state = ReadSetting(QStringLiteral("state")).toByteArray(); - UISettings::values.renderwindow_geometry = - ReadSetting(QStringLiteral("geometryRenderWindow")).toByteArray(); - UISettings::values.gamelist_header_state = - ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray(); - UISettings::values.microprofile_geometry = - ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray(); - - ReadCategory(Settings::Category::UiLayout); - - qt_config->endGroup(); -} - -void Config::ReadWebServiceValues() { - qt_config->beginGroup(QStringLiteral("WebService")); - - ReadCategory(Settings::Category::WebService); - - qt_config->endGroup(); -} - -void Config::ReadMultiplayerValues() { - qt_config->beginGroup(QStringLiteral("Multiplayer")); - - ReadCategory(Settings::Category::Multiplayer); - - // Read ban list back - int size = qt_config->beginReadArray(QStringLiteral("username_ban_list")); - UISettings::values.multiplayer_ban_list.first.resize(size); - for (int i = 0; i < size; ++i) { - qt_config->setArrayIndex(i); - UISettings::values.multiplayer_ban_list.first[i] = - ReadSetting(QStringLiteral("username")).toString().toStdString(); - } - qt_config->endArray(); - size = qt_config->beginReadArray(QStringLiteral("ip_ban_list")); - UISettings::values.multiplayer_ban_list.second.resize(size); - for (int i = 0; i < size; ++i) { - qt_config->setArrayIndex(i); - UISettings::values.multiplayer_ban_list.second[i] = - ReadSetting(QStringLiteral("ip")).toString().toStdString(); - } - qt_config->endArray(); - - qt_config->endGroup(); -} - -void Config::ReadNetworkValues() { - qt_config->beginGroup(QString::fromStdString("Services")); - - ReadCategory(Settings::Category::Network); - - qt_config->endGroup(); -} - -void Config::ReadValues() { - if (global) { - ReadDataStorageValues(); - ReadDebuggingValues(); - ReadDisabledAddOnValues(); - ReadNetworkValues(); - ReadServiceValues(); - ReadUIValues(); - ReadWebServiceValues(); - ReadMiscellaneousValues(); - } - ReadControlValues(); - ReadCoreValues(); - ReadCpuValues(); - ReadRendererValues(); - ReadAudioValues(); - ReadSystemValues(); -} - -void Config::SavePlayerValue(std::size_t player_index) { - const QString player_prefix = [this, player_index] { - if (type == ConfigType::InputProfile) { - return QString{}; - } else { - return QStringLiteral("player_%1_").arg(player_index); - } - }(); - - const auto& player = Settings::values.players.GetValue()[player_index]; - if (IsCustomConfig()) { - if (player.profile_name.empty()) { - // No custom profile selected - return; - } - WriteSetting(QStringLiteral("%1profile_name").arg(player_prefix), - QString::fromStdString(player.profile_name), QString{}); - } - - WriteSetting(QStringLiteral("%1type").arg(player_prefix), - static_cast<u8>(player.controller_type), - static_cast<u8>(Settings::ControllerType::ProController)); - - if (!player_prefix.isEmpty() || !Settings::IsConfiguringGlobal()) { - WriteSetting(QStringLiteral("%1connected").arg(player_prefix), player.connected, - player_index == 0); - WriteSetting(QStringLiteral("%1vibration_enabled").arg(player_prefix), - player.vibration_enabled, true); - WriteSetting(QStringLiteral("%1vibration_strength").arg(player_prefix), - player.vibration_strength, 100); - WriteSetting(QStringLiteral("%1body_color_left").arg(player_prefix), player.body_color_left, - Settings::JOYCON_BODY_NEON_BLUE); - WriteSetting(QStringLiteral("%1body_color_right").arg(player_prefix), - player.body_color_right, Settings::JOYCON_BODY_NEON_RED); - WriteSetting(QStringLiteral("%1button_color_left").arg(player_prefix), - player.button_color_left, Settings::JOYCON_BUTTONS_NEON_BLUE); - WriteSetting(QStringLiteral("%1button_color_right").arg(player_prefix), - player.button_color_right, Settings::JOYCON_BUTTONS_NEON_RED); - } - - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteSetting(QStringLiteral("%1").arg(player_prefix) + - QString::fromStdString(Settings::NativeButton::mapping[i]), - QString::fromStdString(player.buttons[i]), - QString::fromStdString(default_param)); - } - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_stick_mod[i], 0.5f); - WriteSetting(QStringLiteral("%1").arg(player_prefix) + - QString::fromStdString(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(player.analogs[i]), - QString::fromStdString(default_param)); - } - for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); - WriteSetting(QStringLiteral("%1").arg(player_prefix) + - QString::fromStdString(Settings::NativeMotion::mapping[i]), - QString::fromStdString(player.motions[i]), - QString::fromStdString(default_param)); - } -} - -void Config::SaveDebugValues() { - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - WriteSetting(QStringLiteral("debug_pad_") + - QString::fromStdString(Settings::NativeButton::mapping[i]), - QString::fromStdString(Settings::values.debug_pad_buttons[i]), - QString::fromStdString(default_param)); - } - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_stick_mod[i], 0.5f); - WriteSetting(QStringLiteral("debug_pad_") + - QString::fromStdString(Settings::NativeAnalog::mapping[i]), - QString::fromStdString(Settings::values.debug_pad_analogs[i]), - QString::fromStdString(default_param)); - } -} - -void Config::SaveTouchscreenValues() { - const auto& touchscreen = Settings::values.touchscreen; - - WriteSetting(QStringLiteral("touchscreen_enabled"), touchscreen.enabled, true); - - WriteSetting(QStringLiteral("touchscreen_angle"), touchscreen.rotation_angle, 0); - WriteSetting(QStringLiteral("touchscreen_diameter_x"), touchscreen.diameter_x, 15); - WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15); -} - -void Config::SaveMotionTouchValues() { - qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); - for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { - qt_config->setArrayIndex(static_cast<int>(p)); - WriteSetting(QStringLiteral("name"), - QString::fromStdString(Settings::values.touch_from_button_maps[p].name), - QStringLiteral("default")); - qt_config->beginWriteArray(QStringLiteral("entries")); - for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size(); - ++q) { - qt_config->setArrayIndex(static_cast<int>(q)); - WriteSetting( - QStringLiteral("bind"), - QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q])); - } - qt_config->endArray(); - } - qt_config->endArray(); -} - -void Config::SaveHidbusValues() { - const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); - WriteSetting(QStringLiteral("ring_controller"), - QString::fromStdString(Settings::values.ringcon_analogs), - QString::fromStdString(default_param)); -} - -void Config::SaveValues() { - if (global) { - SaveDataStorageValues(); - SaveDebuggingValues(); - SaveDisabledAddOnValues(); - SaveNetworkValues(); - SaveUIValues(); - SaveWebServiceValues(); - SaveMiscellaneousValues(); - } - SaveControlValues(); - SaveCoreValues(); - SaveCpuValues(); - SaveRendererValues(); - SaveAudioValues(); - SaveSystemValues(); - - qt_config->sync(); -} - -void Config::SaveAudioValues() { - qt_config->beginGroup(QStringLiteral("Audio")); - - WriteCategory(Settings::Category::Audio); - WriteCategory(Settings::Category::UiAudio); - - qt_config->endGroup(); -} - -void Config::SaveControlValues() { - qt_config->beginGroup(QStringLiteral("Controls")); - - WriteCategory(Settings::Category::Controls); - - Settings::values.players.SetGlobal(!IsCustomConfig()); - for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { - SavePlayerValue(p); - } - if (IsCustomConfig()) { - qt_config->endGroup(); - return; - } - SaveDebugValues(); - SaveTouchscreenValues(); - SaveMotionTouchValues(); - SaveHidbusValues(); - - qt_config->endGroup(); -} - -void Config::SaveCoreValues() { - qt_config->beginGroup(QStringLiteral("Core")); - - WriteCategory(Settings::Category::Core); - - qt_config->endGroup(); -} - -void Config::SaveDataStorageValues() { - qt_config->beginGroup(QStringLiteral("Data Storage")); - - WriteSetting(QStringLiteral("nand_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); - WriteSetting(QStringLiteral("sdmc_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); - WriteSetting(QStringLiteral("load_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); - WriteSetting(QStringLiteral("dump_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); - WriteSetting(QStringLiteral("tas_directory"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir)), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir))); - - WriteCategory(Settings::Category::DataStorage); - - qt_config->endGroup(); -} - -void Config::SaveDebuggingValues() { - qt_config->beginGroup(QStringLiteral("Debugging")); - - // Intentionally not using the QT default setting as this is intended to be changed in the ini - qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times); - - WriteCategory(Settings::Category::Debugging); - WriteCategory(Settings::Category::DebuggingGraphics); - - qt_config->endGroup(); -} - -void Config::SaveNetworkValues() { - qt_config->beginGroup(QStringLiteral("Services")); - - WriteCategory(Settings::Category::Network); - - qt_config->endGroup(); -} - -void Config::SaveDisabledAddOnValues() { - qt_config->beginWriteArray(QStringLiteral("DisabledAddOns")); - - int i = 0; - for (const auto& elem : Settings::values.disabled_addons) { - qt_config->setArrayIndex(i); - WriteSetting(QStringLiteral("title_id"), QVariant::fromValue<u64>(elem.first), 0); - qt_config->beginWriteArray(QStringLiteral("disabled")); - for (std::size_t j = 0; j < elem.second.size(); ++j) { - qt_config->setArrayIndex(static_cast<int>(j)); - WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), QString{}); - } - qt_config->endArray(); - ++i; - } - - qt_config->endArray(); -} - -void Config::SaveMiscellaneousValues() { - qt_config->beginGroup(QStringLiteral("Miscellaneous")); - - WriteCategory(Settings::Category::Miscellaneous); - - qt_config->endGroup(); -} - -void Config::SavePathValues() { - qt_config->beginGroup(QStringLiteral("Paths")); - - WriteSetting(QStringLiteral("romsPath"), UISettings::values.roms_path); - WriteSetting(QStringLiteral("symbolsPath"), UISettings::values.symbols_path); - qt_config->beginWriteArray(QStringLiteral("gamedirs")); - for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { - qt_config->setArrayIndex(i); - const auto& game_dir = UISettings::values.game_dirs[i]; - WriteSetting(QStringLiteral("path"), game_dir.path); - WriteSetting(QStringLiteral("deep_scan"), game_dir.deep_scan, false); - WriteSetting(QStringLiteral("expanded"), game_dir.expanded, true); - } - qt_config->endArray(); - WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files); - WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{}); - - qt_config->endGroup(); -} - -void Config::SaveCpuValues() { - qt_config->beginGroup(QStringLiteral("Cpu")); - - WriteCategory(Settings::Category::Cpu); - WriteCategory(Settings::Category::CpuDebug); - WriteCategory(Settings::Category::CpuUnsafe); - - qt_config->endGroup(); -} - -void Config::SaveRendererValues() { - qt_config->beginGroup(QStringLiteral("Renderer")); - - WriteCategory(Settings::Category::Renderer); - WriteCategory(Settings::Category::RendererAdvanced); - WriteCategory(Settings::Category::RendererDebug); - - qt_config->endGroup(); -} - -void Config::SaveScreenshotValues() { - qt_config->beginGroup(QStringLiteral("Screenshots")); - - WriteSetting(QStringLiteral("screenshot_path"), - QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir))); - WriteCategory(Settings::Category::Screenshots); - - qt_config->endGroup(); -} - -void Config::SaveShortcutValues() { - qt_config->beginGroup(QStringLiteral("Shortcuts")); - - // Lengths of UISettings::values.shortcuts & default_hotkeys are same. - // However, their ordering must also be the same. - for (std::size_t i = 0; i < default_hotkeys.size(); i++) { - const auto& [name, group, shortcut] = UISettings::values.shortcuts[i]; - const auto& default_hotkey = default_hotkeys[i].shortcut; - - qt_config->beginGroup(group); - qt_config->beginGroup(name); - WriteSetting(QStringLiteral("KeySeq"), shortcut.keyseq, default_hotkey.keyseq); - WriteSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq, - default_hotkey.controller_keyseq); - WriteSetting(QStringLiteral("Context"), shortcut.context, default_hotkey.context); - WriteSetting(QStringLiteral("Repeat"), shortcut.repeat, default_hotkey.repeat); - qt_config->endGroup(); - qt_config->endGroup(); - } - - qt_config->endGroup(); -} - -void Config::SaveSystemValues() { - qt_config->beginGroup(QStringLiteral("System")); - - WriteCategory(Settings::Category::System); - WriteCategory(Settings::Category::SystemAudio); - - qt_config->endGroup(); -} - -void Config::SaveUIValues() { - qt_config->beginGroup(QStringLiteral("UI")); - - WriteCategory(Settings::Category::Ui); - WriteCategory(Settings::Category::UiGeneral); - - WriteSetting(QStringLiteral("theme"), UISettings::values.theme, - QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second)); - - SaveUIGamelistValues(); - SaveUILayoutValues(); - SavePathValues(); - SaveScreenshotValues(); - SaveShortcutValues(); - SaveMultiplayerValues(); - - qt_config->endGroup(); -} - -void Config::SaveUIGamelistValues() { - qt_config->beginGroup(QStringLiteral("UIGameList")); - - WriteCategory(Settings::Category::UiGameList); - - qt_config->beginWriteArray(QStringLiteral("favorites")); - for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { - qt_config->setArrayIndex(i); - WriteSetting(QStringLiteral("program_id"), - QVariant::fromValue(UISettings::values.favorited_ids[i])); - } - qt_config->endArray(); - - qt_config->endGroup(); -} - -void Config::SaveUILayoutValues() { - qt_config->beginGroup(QStringLiteral("UILayout")); - - WriteSetting(QStringLiteral("geometry"), UISettings::values.geometry); - WriteSetting(QStringLiteral("state"), UISettings::values.state); - WriteSetting(QStringLiteral("geometryRenderWindow"), UISettings::values.renderwindow_geometry); - WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state); - WriteSetting(QStringLiteral("microProfileDialogGeometry"), - UISettings::values.microprofile_geometry); - - WriteCategory(Settings::Category::UiLayout); - - qt_config->endGroup(); -} - -void Config::SaveWebServiceValues() { - qt_config->beginGroup(QStringLiteral("WebService")); - - WriteCategory(Settings::Category::WebService); - - qt_config->endGroup(); -} - -void Config::SaveMultiplayerValues() { - qt_config->beginGroup(QStringLiteral("Multiplayer")); - - WriteCategory(Settings::Category::Multiplayer); - - // Write ban list - qt_config->beginWriteArray(QStringLiteral("username_ban_list")); - for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { - qt_config->setArrayIndex(static_cast<int>(i)); - WriteSetting(QStringLiteral("username"), - QString::fromStdString(UISettings::values.multiplayer_ban_list.first[i])); - } - qt_config->endArray(); - qt_config->beginWriteArray(QStringLiteral("ip_ban_list")); - for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { - qt_config->setArrayIndex(static_cast<int>(i)); - WriteSetting(QStringLiteral("ip"), - QString::fromStdString(UISettings::values.multiplayer_ban_list.second[i])); - } - qt_config->endArray(); - - qt_config->endGroup(); -} - -QVariant Config::ReadSetting(const QString& name) const { - return qt_config->value(name); -} - -QVariant Config::ReadSetting(const QString& name, const QVariant& default_value) const { - QVariant result; - if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) { - result = default_value; - } else { - result = qt_config->value(name, default_value); - } - return result; -} - -void Config::WriteSetting(const QString& name, const QVariant& value) { - qt_config->setValue(name, value); -} - -void Config::WriteSetting(const QString& name, const QVariant& value, - const QVariant& default_value) { - qt_config->setValue(name + QStringLiteral("/default"), value == default_value); - qt_config->setValue(name, value); -} - -void Config::WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value, - bool use_global) { - if (!global) { - qt_config->setValue(name + QStringLiteral("/use_global"), use_global); - } - if (global || !use_global) { - qt_config->setValue(name + QStringLiteral("/default"), value == default_value); - qt_config->setValue(name, value); - } -} - -void Config::Reload() { - ReadValues(); - // To apply default value changes - SaveValues(); -} - -void Config::Save() { - SaveValues(); -} - -void Config::ReadControlPlayerValue(std::size_t player_index) { - qt_config->beginGroup(QStringLiteral("Controls")); - ReadPlayerValue(player_index); - qt_config->endGroup(); -} - -void Config::SaveControlPlayerValue(std::size_t player_index) { - qt_config->beginGroup(QStringLiteral("Controls")); - SavePlayerValue(player_index); - qt_config->endGroup(); -} - -void Config::ClearControlPlayerValues() { - qt_config->beginGroup(QStringLiteral("Controls")); - // If key is an empty string, all keys in the current group() are removed. - qt_config->remove(QString{}); - qt_config->endGroup(); -} - -const std::string& Config::GetConfigFilePath() const { - return qt_config_loc; -} - -static auto FindRelevantList(Settings::Category category) { - auto& map = Settings::values.linkage.by_category; - if (map.contains(category)) { - return Settings::values.linkage.by_category[category]; - } - return UISettings::values.linkage.by_category[category]; -} - -void Config::ReadCategory(Settings::Category category) { - const auto& settings = FindRelevantList(category); - std::for_each(settings.begin(), settings.end(), - [&](const auto& setting) { ReadSettingGeneric(setting); }); -} - -void Config::WriteCategory(Settings::Category category) { - const auto& settings = FindRelevantList(category); - std::for_each(settings.begin(), settings.end(), - [&](const auto& setting) { WriteSettingGeneric(setting); }); -} - -void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) { - if (!setting->Save() || (!setting->Switchable() && !global)) { - return; - } - const QString name = QString::fromStdString(setting->GetLabel()); - const auto default_value = - QVariant::fromValue<QString>(QString::fromStdString(setting->DefaultToString())); - - bool use_global = true; - if (setting->Switchable() && !global) { - use_global = qt_config->value(name + QStringLiteral("/use_global"), true).value<bool>(); - setting->SetGlobal(use_global); - } - - if (global || !use_global) { - const bool is_default = - qt_config->value(name + QStringLiteral("/default"), true).value<bool>(); - if (!is_default) { - setting->LoadString( - qt_config->value(name, default_value).value<QString>().toStdString()); - } else { - // Empty string resets the Setting to default - setting->LoadString(""); - } - } -} - -void Config::WriteSettingGeneric(Settings::BasicSetting* const setting) const { - if (!setting->Save()) { - return; - } - const QVariant value = QVariant::fromValue(QString::fromStdString(setting->ToString())); - const QVariant default_value = - QVariant::fromValue(QString::fromStdString(setting->DefaultToString())); - const QString label = QString::fromStdString(setting->GetLabel()); - if (setting->Switchable()) { - if (!global) { - qt_config->setValue(label + QStringLiteral("/use_global"), setting->UsingGlobal()); - } - if (global || !setting->UsingGlobal()) { - qt_config->setValue(label + QStringLiteral("/default"), value == default_value); - qt_config->setValue(label, value); - } - } else if (global) { - qt_config->setValue(label + QStringLiteral("/default"), value == default_value); - qt_config->setValue(label, value); - } -} diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h deleted file mode 100644 index 1589ba057..000000000 --- a/src/yuzu/configuration/config.h +++ /dev/null @@ -1,179 +0,0 @@ -// SPDX-FileCopyrightText: 2014 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <array> -#include <memory> -#include <string> -#include <QMetaType> -#include <QVariant> -#include "common/settings.h" -#include "common/settings_enums.h" -#include "yuzu/uisettings.h" - -class QSettings; - -namespace Core { -class System; -} - -class Config { -public: - enum class ConfigType { - GlobalConfig, - PerGameConfig, - InputProfile, - }; - - explicit Config(const std::string& config_name = "qt-config", - ConfigType config_type = ConfigType::GlobalConfig); - ~Config(); - - void Reload(); - void Save(); - - void ReadControlPlayerValue(std::size_t player_index); - void SaveControlPlayerValue(std::size_t player_index); - void ClearControlPlayerValues(); - - const std::string& GetConfigFilePath() const; - - static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; - static const std::array<int, Settings::NativeMotion::NumMotions> default_motions; - static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; - static const std::array<int, 2> default_stick_mod; - static const std::array<int, 2> default_ringcon_analogs; - static const std::array<int, Settings::NativeMouseButton::NumMouseButtons> - default_mouse_buttons; - 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<UISettings::Shortcut, 23> default_hotkeys; - - static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map; - static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map; - static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map; - static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map; - static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map; - static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map; - - static constexpr UISettings::Theme default_theme{ -#ifdef _WIN32 - UISettings::Theme::DarkColorful -#else - UISettings::Theme::DefaultColorful -#endif - }; - -private: - void Initialize(const std::string& config_name); - bool IsCustomConfig(); - - void ReadValues(); - void ReadPlayerValue(std::size_t player_index); - void ReadDebugValues(); - void ReadKeyboardValues(); - void ReadMouseValues(); - void ReadTouchscreenValues(); - void ReadMotionTouchValues(); - void ReadHidbusValues(); - void ReadIrCameraValues(); - - // Read functions bases off the respective config section names. - void ReadAudioValues(); - void ReadControlValues(); - void ReadCoreValues(); - void ReadDataStorageValues(); - void ReadDebuggingValues(); - void ReadServiceValues(); - void ReadDisabledAddOnValues(); - void ReadMiscellaneousValues(); - void ReadPathValues(); - void ReadCpuValues(); - void ReadRendererValues(); - void ReadScreenshotValues(); - void ReadShortcutValues(); - void ReadSystemValues(); - void ReadUIValues(); - void ReadUIGamelistValues(); - void ReadUILayoutValues(); - void ReadWebServiceValues(); - void ReadMultiplayerValues(); - void ReadNetworkValues(); - - void SaveValues(); - void SavePlayerValue(std::size_t player_index); - void SaveDebugValues(); - void SaveMouseValues(); - void SaveTouchscreenValues(); - void SaveMotionTouchValues(); - void SaveHidbusValues(); - void SaveIrCameraValues(); - - // Save functions based off the respective config section names. - void SaveAudioValues(); - void SaveControlValues(); - void SaveCoreValues(); - void SaveDataStorageValues(); - void SaveDebuggingValues(); - void SaveNetworkValues(); - void SaveDisabledAddOnValues(); - void SaveMiscellaneousValues(); - void SavePathValues(); - void SaveCpuValues(); - void SaveRendererValues(); - void SaveScreenshotValues(); - void SaveShortcutValues(); - void SaveSystemValues(); - void SaveUIValues(); - void SaveUIGamelistValues(); - void SaveUILayoutValues(); - void SaveWebServiceValues(); - void SaveMultiplayerValues(); - - /** - * Reads a setting from the qt_config. - * - * @param name The setting's identifier - * @param default_value The value to use when the setting is not already present in the config - */ - QVariant ReadSetting(const QString& name) const; - QVariant ReadSetting(const QString& name, const QVariant& default_value) const; - - /** - * Writes a setting to the qt_config. - * - * @param name The setting's idetentifier - * @param value Value of the setting - * @param default_value Default of the setting if not present in qt_config - * @param use_global Specifies if the custom or global config should be in use, for custom - * configs - */ - void WriteSetting(const QString& name, const QVariant& value); - void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); - void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value, - bool use_global); - - void ReadCategory(Settings::Category category); - void WriteCategory(Settings::Category category); - void ReadSettingGeneric(Settings::BasicSetting* const setting); - void WriteSettingGeneric(Settings::BasicSetting* const setting) const; - - const ConfigType type; - std::unique_ptr<QSettings> qt_config; - std::string qt_config_loc; - const bool global; -}; - -// These metatype declarations cannot be in common/settings.h because core is devoid of QT -Q_DECLARE_METATYPE(Settings::CpuAccuracy); -Q_DECLARE_METATYPE(Settings::GpuAccuracy); -Q_DECLARE_METATYPE(Settings::FullscreenMode); -Q_DECLARE_METATYPE(Settings::NvdecEmulation); -Q_DECLARE_METATYPE(Settings::ResolutionSetup); -Q_DECLARE_METATYPE(Settings::ScalingFilter); -Q_DECLARE_METATYPE(Settings::AntiAliasing); -Q_DECLARE_METATYPE(Settings::RendererBackend); -Q_DECLARE_METATYPE(Settings::ShaderBackend); -Q_DECLARE_METATYPE(Settings::AstcRecompression); -Q_DECLARE_METATYPE(Settings::AstcDecodeMode); diff --git a/src/yuzu/configuration/configure_camera.cpp b/src/yuzu/configuration/configure_camera.cpp index d95e96696..3368f53f3 100644 --- a/src/yuzu/configuration/configure_camera.cpp +++ b/src/yuzu/configuration/configure_camera.cpp @@ -10,10 +10,10 @@ #include <QStandardItemModel> #include <QTimer> +#include "common/settings.h" #include "input_common/drivers/camera.h" #include "input_common/main.h" #include "ui_configure_camera.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_camera.h" ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 0ad95cc02..aab54a1cc 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -8,7 +8,6 @@ #include "core/core.h" #include "ui_configure.h" #include "vk_device_info.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_audio.h" #include "yuzu/configuration/configure_cpu.h" #include "yuzu/configuration/configure_debug_tab.h" diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 68e21cd84..76fc33e49 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp @@ -9,10 +9,11 @@ #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" +#include "frontend_common/config.h" #include "ui_configure_hotkeys.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_hotkeys.h" #include "yuzu/hotkeys.h" +#include "yuzu/uisettings.h" #include "yuzu/util/sequence_dialog/sequence_dialog.h" constexpr int name_column = 0; @@ -62,18 +63,21 @@ ConfigureHotkeys::~ConfigureHotkeys() = default; void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { for (const auto& group : registry.hotkey_groups) { + QString parent_item_data = QString::fromStdString(group.first); auto* parent_item = - new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(group.first))); + new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(parent_item_data))); parent_item->setEditable(false); - parent_item->setData(group.first); + parent_item->setData(parent_item_data); for (const auto& hotkey : group.second) { - auto* action = - new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(hotkey.first))); + QString hotkey_action_data = QString::fromStdString(hotkey.first); + auto* action = new QStandardItem( + QCoreApplication::translate("Hotkeys", qPrintable(hotkey_action_data))); auto* keyseq = new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); - auto* controller_keyseq = new QStandardItem(hotkey.second.controller_keyseq); + auto* controller_keyseq = + new QStandardItem(QString::fromStdString(hotkey.second.controller_keyseq)); action->setEditable(false); - action->setData(hotkey.first); + action->setData(hotkey_action_data); keyseq->setEditable(false); controller_keyseq->setEditable(false); parent_item->appendRow({action, keyseq, controller_keyseq}); @@ -301,13 +305,13 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { const QStandardItem* controller_keyseq = parent->child(key_column_id, controller_column); for (auto& [group, sub_actions] : registry.hotkey_groups) { - if (group != parent->data()) + if (group != parent->data().toString().toStdString()) continue; for (auto& [action_name, hotkey] : sub_actions) { - if (action_name != action->data()) + if (action_name != action->data().toString().toStdString()) continue; hotkey.keyseq = QKeySequence(keyseq->text()); - hotkey.controller_keyseq = controller_keyseq->text(); + hotkey.controller_keyseq = controller_keyseq->text().toStdString(); } } } @@ -319,7 +323,7 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { void ConfigureHotkeys::RestoreDefaults() { for (int r = 0; r < model->rowCount(); ++r) { const QStandardItem* parent = model->item(r, 0); - const int hotkey_size = static_cast<int>(Config::default_hotkeys.size()); + const int hotkey_size = static_cast<int>(UISettings::default_hotkeys.size()); if (hotkey_size != parent->rowCount()) { QMessageBox::warning(this, tr("Invalid hotkey settings"), @@ -330,10 +334,11 @@ void ConfigureHotkeys::RestoreDefaults() { for (int r2 = 0; r2 < parent->rowCount(); ++r2) { model->item(r, 0) ->child(r2, hotkey_column) - ->setText(Config::default_hotkeys[r2].shortcut.keyseq); + ->setText(QString::fromStdString(UISettings::default_hotkeys[r2].shortcut.keyseq)); model->item(r, 0) ->child(r2, controller_column) - ->setText(Config::default_hotkeys[r2].shortcut.controller_keyseq); + ->setText(QString::fromStdString( + UISettings::default_hotkeys[r2].shortcut.controller_keyseq)); } } } @@ -379,7 +384,7 @@ void ConfigureHotkeys::PopupContextMenu(const QPoint& menu_location) { void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) { const QString& default_key_sequence = - Config::default_hotkeys[index.row()].shortcut.controller_keyseq; + QString::fromStdString(UISettings::default_hotkeys[index.row()].shortcut.controller_keyseq); const auto [key_sequence_used, used_action] = IsUsedControllerKey(default_key_sequence); if (key_sequence_used && default_key_sequence != model->data(index).toString()) { @@ -393,7 +398,8 @@ void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) { void ConfigureHotkeys::RestoreHotkey(QModelIndex index) { const QKeySequence& default_key_sequence = QKeySequence::fromString( - Config::default_hotkeys[index.row()].shortcut.keyseq, QKeySequence::NativeText); + QString::fromStdString(UISettings::default_hotkeys[index.row()].shortcut.keyseq), + QKeySequence::NativeText); const auto [key_sequence_used, used_action] = IsUsedKey(default_key_sequence); if (key_sequence_used && default_key_sequence != QKeySequence(model->data(index).toString())) { diff --git a/src/yuzu/configuration/configure_input_per_game.cpp b/src/yuzu/configuration/configure_input_per_game.cpp index 78e65d468..8d9f65a05 100644 --- a/src/yuzu/configuration/configure_input_per_game.cpp +++ b/src/yuzu/configuration/configure_input_per_game.cpp @@ -5,12 +5,12 @@ #include "core/core.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" +#include "frontend_common/config.h" #include "ui_configure_input_per_game.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input_per_game.h" #include "yuzu/configuration/input_profiles.h" -ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, Config* config_, +ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, QtConfig* config_, QWidget* parent) : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPerGame>()), profiles(std::make_unique<InputProfiles>()), system{system_}, config{config_} { @@ -110,6 +110,6 @@ void ConfigureInputPerGame::SaveConfiguration() { // Clear all controls from the config in case the user reverted back to globals config->ClearControlPlayerValues(); for (size_t index = 0; index < Settings::values.players.GetValue().size(); ++index) { - config->SaveControlPlayerValue(index); + config->SaveQtControlPlayerValues(index); } } diff --git a/src/yuzu/configuration/configure_input_per_game.h b/src/yuzu/configuration/configure_input_per_game.h index 660faf574..4420e856c 100644 --- a/src/yuzu/configuration/configure_input_per_game.h +++ b/src/yuzu/configuration/configure_input_per_game.h @@ -9,6 +9,7 @@ #include "ui_configure_input_per_game.h" #include "yuzu/configuration/input_profiles.h" +#include "yuzu/configuration/qt_config.h" class QComboBox; @@ -22,7 +23,7 @@ class ConfigureInputPerGame : public QWidget { Q_OBJECT public: - explicit ConfigureInputPerGame(Core::System& system_, Config* config_, + explicit ConfigureInputPerGame(Core::System& system_, QtConfig* config_, QWidget* parent = nullptr); /// Load and Save configurations to settings file. @@ -41,5 +42,5 @@ private: std::array<QComboBox*, 8> profile_comboboxes; Core::System& system; - Config* config; + QtConfig* config; }; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 9259e2a5d..0f7b3714e 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -12,15 +12,16 @@ #include <QTimer> #include "common/assert.h" #include "common/param_package.h" +#include "configuration/qt_config.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" +#include "frontend_common/config.h" #include "input_common/drivers/keyboard.h" #include "input_common/drivers/mouse.h" #include "input_common/main.h" #include "ui_configure_input_player.h" #include "yuzu/bootmanager.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/configuration/configure_mouse_panning.h" @@ -1397,25 +1398,25 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { emulated_controller->SetButtonParam( button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_buttons[button_id])}); + QtConfig::default_buttons[button_id])}); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { Common::ParamPackage analog_param{}; for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { Common::ParamPackage params{InputCommon::GenerateKeyboardParam( - Config::default_analogs[analog_id][sub_button_id])}; + QtConfig::default_analogs[analog_id][sub_button_id])}; SetAnalogParam(params, analog_param, analog_sub_buttons[sub_button_id]); } analog_param.Set("modifier", InputCommon::GenerateKeyboardParam( - Config::default_stick_mod[analog_id])); + QtConfig::default_stick_mod[analog_id])); emulated_controller->SetStickParam(analog_id, analog_param); } for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { emulated_controller->SetMotionParam( motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_motions[motion_id])}); + QtConfig::default_motions[motion_id])}); } // If mouse is selected we want to override with mappings from the driver diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index b91d6ad4a..b274a3321 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -25,8 +25,8 @@ #include "core/file_sys/patch_manager.h" #include "core/file_sys/xts_archive.h" #include "core/loader/loader.h" +#include "frontend_common/config.h" #include "ui_configure_per_game.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_audio.h" #include "yuzu/configuration/configure_cpu.h" @@ -50,8 +50,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) : fmt::format("{:016X}", title_id); - game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig); - + game_config = std::make_unique<QtConfig>(config_file_name, Config::ConfigType::PerGameConfig); addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this); audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this); cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this); @@ -108,7 +107,7 @@ void ConfigurePerGame::ApplyConfiguration() { system.ApplySettings(); Settings::LogSettings(); - game_config->Save(); + game_config->SaveAllValues(); } void ConfigurePerGame::changeEvent(QEvent* event) { diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index cc2513001..c8ee46c04 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h @@ -12,9 +12,10 @@ #include "configuration/shared_widget.h" #include "core/file_sys/vfs_types.h" +#include "frontend_common/config.h" #include "vk_device_info.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configuration_shared.h" +#include "yuzu/configuration/qt_config.h" #include "yuzu/configuration/shared_translation.h" namespace Core { @@ -72,7 +73,7 @@ private: QGraphicsScene* scene; - std::unique_ptr<Config> game_config; + std::unique_ptr<QtConfig> game_config; Core::System& system; std::unique_ptr<ConfigurationShared::Builder> builder; diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 674a75a62..140a7fe5d 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -19,7 +19,6 @@ #include "core/file_sys/xts_archive.h" #include "core/loader/loader.h" #include "ui_configure_per_game_addons.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_input.h" #include "yuzu/configuration/configure_per_game_addons.h" #include "yuzu/uisettings.h" diff --git a/src/yuzu/configuration/configure_ringcon.cpp b/src/yuzu/configuration/configure_ringcon.cpp index f83705544..9572ff43c 100644 --- a/src/yuzu/configuration/configure_ringcon.cpp +++ b/src/yuzu/configuration/configure_ringcon.cpp @@ -8,6 +8,7 @@ #include <QTimer> #include <fmt/format.h> +#include "configuration/qt_config.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "input_common/drivers/keyboard.h" @@ -15,7 +16,6 @@ #include "input_common/main.h" #include "ui_configure_ringcon.h" #include "yuzu/bootmanager.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_ringcon.h" const std::array<std::string, ConfigureRingController::ANALOG_SUB_BUTTONS_NUM> @@ -270,7 +270,7 @@ void ConfigureRingController::LoadConfiguration() { void ConfigureRingController::RestoreDefaults() { const std::string default_ring_string = InputCommon::GenerateAnalogParamFromKeys( - 0, 0, Config::default_ringcon_analogs[0], Config::default_ringcon_analogs[1], 0, 0.05f); + 0, 0, QtConfig::default_ringcon_analogs[0], QtConfig::default_ringcon_analogs[1], 0, 0.05f); emulated_controller->SetRingParam(Common::ParamPackage(default_ring_string)); UpdateUI(); } diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 0c8e5c8b4..7cbf43775 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -16,7 +16,6 @@ #include "core/core.h" #include "core/hle/service/time/time_manager.h" #include "ui_configure_system.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_system.h" #include "yuzu/configuration/shared_widget.h" diff --git a/src/yuzu/configuration/configure_touchscreen_advanced.cpp b/src/yuzu/configuration/configure_touchscreen_advanced.cpp index 5a03e48df..94df6d9d3 100644 --- a/src/yuzu/configuration/configure_touchscreen_advanced.cpp +++ b/src/yuzu/configuration/configure_touchscreen_advanced.cpp @@ -2,8 +2,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <memory> +#include "common/settings.h" #include "ui_configure_touchscreen_advanced.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent) diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 82f3b6e78..dd43f0a0e 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -164,7 +164,7 @@ ConfigureUi::~ConfigureUi() = default; void ConfigureUi::ApplyConfiguration() { UISettings::values.theme = - ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); + ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString().toStdString(); UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); UISettings::values.show_compat = ui->show_compat->isChecked(); UISettings::values.show_size = ui->show_size->isChecked(); @@ -191,9 +191,10 @@ void ConfigureUi::RequestGameListUpdate() { } void ConfigureUi::SetConfiguration() { - ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); + ui->theme_combobox->setCurrentIndex( + ui->theme_combobox->findData(QString::fromStdString(UISettings::values.theme))); ui->language_combobox->setCurrentIndex( - ui->language_combobox->findData(UISettings::values.language)); + ui->language_combobox->findData(QString::fromStdString(UISettings::values.language))); ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); ui->show_size->setChecked(UISettings::values.show_size.GetValue()); diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp index 41ef4250a..716efbccd 100644 --- a/src/yuzu/configuration/input_profiles.cpp +++ b/src/yuzu/configuration/input_profiles.cpp @@ -5,7 +5,7 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" -#include "yuzu/configuration/config.h" +#include "frontend_common/config.h" #include "yuzu/configuration/input_profiles.h" namespace FS = Common::FS; @@ -44,7 +44,7 @@ InputProfiles::InputProfiles() { if (IsINI(filename) && IsProfileNameValid(name_without_ext)) { map_profiles.insert_or_assign( name_without_ext, - std::make_unique<Config>(name_without_ext, Config::ConfigType::InputProfile)); + std::make_unique<QtConfig>(name_without_ext, Config::ConfigType::InputProfile)); } return true; @@ -85,7 +85,7 @@ bool InputProfiles::CreateProfile(const std::string& profile_name, std::size_t p } map_profiles.insert_or_assign( - profile_name, std::make_unique<Config>(profile_name, Config::ConfigType::InputProfile)); + profile_name, std::make_unique<QtConfig>(profile_name, Config::ConfigType::InputProfile)); return SaveProfile(profile_name, player_index); } @@ -113,7 +113,7 @@ bool InputProfiles::LoadProfile(const std::string& profile_name, std::size_t pla return false; } - map_profiles[profile_name]->ReadControlPlayerValue(player_index); + map_profiles[profile_name]->ReadQtControlPlayerValues(player_index); return true; } @@ -122,7 +122,7 @@ bool InputProfiles::SaveProfile(const std::string& profile_name, std::size_t pla return false; } - map_profiles[profile_name]->SaveControlPlayerValue(player_index); + map_profiles[profile_name]->SaveQtControlPlayerValues(player_index); return true; } diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h index 2bf3e4250..023ec74a6 100644 --- a/src/yuzu/configuration/input_profiles.h +++ b/src/yuzu/configuration/input_profiles.h @@ -6,6 +6,8 @@ #include <string> #include <unordered_map> +#include "configuration/qt_config.h" + namespace Core { class System; } @@ -30,5 +32,5 @@ public: private: bool ProfileExistsInMap(const std::string& profile_name) const; - std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles; + std::unordered_map<std::string, std::unique_ptr<QtConfig>> map_profiles; }; diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp new file mode 100644 index 000000000..5a8e69aa9 --- /dev/null +++ b/src/yuzu/configuration/qt_config.cpp @@ -0,0 +1,549 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "input_common/main.h" +#include "qt_config.h" +#include "uisettings.h" + +const std::array<int, Settings::NativeButton::NumButtons> QtConfig::default_buttons = { + Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F, + Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T, + Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, + Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0, + Qt::Key_Q, Qt::Key_E, +}; + +const std::array<int, Settings::NativeMotion::NumMotions> QtConfig::default_motions = { + Qt::Key_7, + Qt::Key_8, +}; + +const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{ + { + Qt::Key_W, + Qt::Key_S, + Qt::Key_A, + Qt::Key_D, + }, + { + Qt::Key_I, + Qt::Key_K, + Qt::Key_J, + Qt::Key_L, + }, +}}; + +const std::array<int, 2> QtConfig::default_stick_mod = { + Qt::Key_Shift, + 0, +}; + +const std::array<int, 2> QtConfig::default_ringcon_analogs{{ + Qt::Key_A, + Qt::Key_D, +}}; + +QtConfig::QtConfig(const std::string& config_name, const ConfigType config_type) + : Config(config_type) { + Initialize(config_name); + if (config_type != ConfigType::InputProfile) { + ReadQtValues(); + SaveQtValues(); + } +} + +QtConfig::~QtConfig() { + if (global) { + QtConfig::SaveAllValues(); + } +} + +void QtConfig::ReloadAllValues() { + Reload(); + ReadQtValues(); + SaveQtValues(); +} + +void QtConfig::SaveAllValues() { + Save(); + SaveQtValues(); +} + +void QtConfig::ReadQtValues() { + if (global) { + ReadUIValues(); + } + ReadQtControlValues(); +} + +void QtConfig::ReadQtPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix.append("player_").append(ToString(player_index)).append("_"); + } + + auto& player = Settings::values.players.GetValue()[player_index]; + if (IsCustomConfig()) { + const auto profile_name = + ReadStringSetting(std::string(player_prefix).append("profile_name")); + if (profile_name.empty()) { + // Use the global input config + player = Settings::values.players.GetValue(true)[player_index]; + return; + } + } + + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + auto& player_buttons = player.buttons[i]; + + player_buttons = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param); + if (player_buttons.empty()) { + player_buttons = default_param; + } + } + + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + auto& player_analogs = player.analogs[i]; + + player_analogs = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param); + if (player_analogs.empty()) { + player_analogs = default_param; + } + } + + for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); + auto& player_motions = player.motions[i]; + + player_motions = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param); + if (player_motions.empty()) { + player_motions = default_param; + } + } +} + +void QtConfig::ReadHidbusValues() { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + auto& ringcon_analogs = Settings::values.ringcon_analogs; + + ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param); + if (ringcon_analogs.empty()) { + ringcon_analogs = default_param; + } +} + +void QtConfig::ReadDebugControlValues() { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; + + debug_pad_buttons = ReadStringSetting( + std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param); + if (debug_pad_buttons.empty()) { + debug_pad_buttons = default_param; + } + } + + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; + + debug_pad_analogs = ReadStringSetting( + std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param); + if (debug_pad_analogs.empty()) { + debug_pad_analogs = default_param; + } + } +} + +void QtConfig::ReadQtControlValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { + ReadQtPlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + ReadDebugControlValues(); + ReadHidbusValues(); + + EndGroup(); +} + +void QtConfig::ReadPathValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); + + UISettings::values.roms_path = ReadStringSetting(std::string("romsPath")); + UISettings::values.symbols_path = ReadStringSetting(std::string("symbolsPath")); + UISettings::values.game_dir_deprecated = + ReadStringSetting(std::string("gameListRootDir"), std::string(".")); + UISettings::values.game_dir_deprecated_deepscan = + ReadBooleanSetting(std::string("gameListDeepScan"), std::make_optional(false)); + + const int gamedirs_size = BeginArray(std::string("gamedirs")); + for (int i = 0; i < gamedirs_size; ++i) { + SetArrayIndex(i); + UISettings::GameDir game_dir; + game_dir.path = ReadStringSetting(std::string("path")); + game_dir.deep_scan = + ReadBooleanSetting(std::string("deep_scan"), std::make_optional(false)); + game_dir.expanded = ReadBooleanSetting(std::string("expanded"), std::make_optional(true)); + UISettings::values.game_dirs.append(game_dir); + } + EndArray(); + + // Create NAND and SD card directories if empty, these are not removable through the UI, + // also carries over old game list settings if present + if (UISettings::values.game_dirs.empty()) { + UISettings::GameDir game_dir; + game_dir.path = std::string("SDMC"); + game_dir.expanded = true; + UISettings::values.game_dirs.append(game_dir); + game_dir.path = std::string("UserNAND"); + UISettings::values.game_dirs.append(game_dir); + game_dir.path = std::string("SysNAND"); + UISettings::values.game_dirs.append(game_dir); + if (UISettings::values.game_dir_deprecated != std::string(".")) { + game_dir.path = UISettings::values.game_dir_deprecated; + game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan; + UISettings::values.game_dirs.append(game_dir); + } + } + UISettings::values.recent_files = + QString::fromStdString(ReadStringSetting(std::string("recentFiles"))) + .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive); + UISettings::values.language = ReadStringSetting(std::string("language"), std::string("")); + + EndGroup(); +} + +void QtConfig::ReadShortcutValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts)); + + for (const auto& [name, group, shortcut] : UISettings::default_hotkeys) { + BeginGroup(group); + BeginGroup(name); + + // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1 + // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open + // a file dialog in windowed mode + UISettings::values.shortcuts.push_back( + {name, + group, + {ReadStringSetting(std::string("KeySeq"), shortcut.keyseq), + ReadStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq), + shortcut.context, + ReadBooleanSetting(std::string("Repeat"), std::optional(shortcut.repeat))}}); + + EndGroup(); // name + EndGroup(); // group + } + + EndGroup(); +} + +void QtConfig::ReadUIValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Ui)); + + UISettings::values.theme = ReadStringSetting( + std::string("theme"), + std::string(UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second)); + + ReadUIGamelistValues(); + ReadUILayoutValues(); + ReadPathValues(); + ReadScreenshotValues(); + ReadShortcutValues(); + ReadMultiplayerValues(); + + ReadCategory(Settings::Category::Ui); + ReadCategory(Settings::Category::UiGeneral); + + EndGroup(); +} + +void QtConfig::ReadUIGamelistValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); + + ReadCategory(Settings::Category::UiGameList); + + const int favorites_size = BeginArray("favorites"); + for (int i = 0; i < favorites_size; i++) { + SetArrayIndex(i); + UISettings::values.favorited_ids.append( + ReadUnsignedIntegerSetting(std::string("program_id"))); + } + EndArray(); + + EndGroup(); +} + +void QtConfig::ReadUILayoutValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); + + ReadCategory(Settings::Category::UiLayout); + + EndGroup(); +} + +void QtConfig::ReadMultiplayerValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Multiplayer)); + + ReadCategory(Settings::Category::Multiplayer); + + // Read ban list back + int size = BeginArray(std::string("username_ban_list")); + UISettings::values.multiplayer_ban_list.first.resize(size); + for (int i = 0; i < size; ++i) { + SetArrayIndex(i); + UISettings::values.multiplayer_ban_list.first[i] = + ReadStringSetting(std::string("username"), std::string("")); + } + EndArray(); + + size = BeginArray(std::string("ip_ban_list")); + UISettings::values.multiplayer_ban_list.second.resize(size); + for (int i = 0; i < size; ++i) { + UISettings::values.multiplayer_ban_list.second[i] = + ReadStringSetting("username", std::string("")); + } + EndArray(); + + EndGroup(); +} + +void QtConfig::SaveQtValues() { + if (global) { + SaveUIValues(); + } + SaveQtControlValues(); + + WriteToIni(); +} + +void QtConfig::SaveQtPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix = std::string("player_").append(ToString(player_index)).append("_"); + } + + const auto& player = Settings::values.players.GetValue()[player_index]; + if (IsCustomConfig() && player.profile_name.empty()) { + // No custom profile selected + return; + } + + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), + player.buttons[i], std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), + player.analogs[i], std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); + WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), + player.motions[i], std::make_optional(default_param)); + } +} + +void QtConfig::SaveDebugControlValues() { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), + Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), + Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); + } +} + +void QtConfig::SaveHidbusValues() { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, + std::make_optional(default_param)); +} + +void QtConfig::SaveQtControlValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { + SaveQtPlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + SaveDebugControlValues(); + SaveHidbusValues(); + + EndGroup(); +} + +void QtConfig::SavePathValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Paths)); + + WriteSetting(std::string("romsPath"), UISettings::values.roms_path); + WriteSetting(std::string("symbolsPath"), UISettings::values.symbols_path); + BeginArray(std::string("gamedirs")); + for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { + SetArrayIndex(i); + const auto& game_dir = UISettings::values.game_dirs[i]; + WriteSetting(std::string("path"), game_dir.path); + WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false)); + WriteSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true)); + } + EndArray(); + + WriteSetting(std::string("recentFiles"), + UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString()); + WriteSetting(std::string("language"), UISettings::values.language); + + EndGroup(); +} + +void QtConfig::SaveShortcutValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts)); + + // Lengths of UISettings::values.shortcuts & default_hotkeys are same. + // However, their ordering must also be the same. + for (std::size_t i = 0; i < UISettings::default_hotkeys.size(); i++) { + const auto& [name, group, shortcut] = UISettings::values.shortcuts[i]; + const auto& default_hotkey = UISettings::default_hotkeys[i].shortcut; + + BeginGroup(group); + BeginGroup(name); + + WriteSetting(std::string("KeySeq"), shortcut.keyseq, + std::make_optional(default_hotkey.keyseq)); + WriteSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq, + std::make_optional(default_hotkey.controller_keyseq)); + WriteSetting(std::string("Context"), shortcut.context, + std::make_optional(default_hotkey.context)); + WriteSetting(std::string("Repeat"), shortcut.repeat, + std::make_optional(default_hotkey.repeat)); + + EndGroup(); // name + EndGroup(); // group + } + + EndGroup(); +} + +void QtConfig::SaveUIValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Ui)); + + WriteCategory(Settings::Category::Ui); + WriteCategory(Settings::Category::UiGeneral); + + WriteSetting(std::string("theme"), UISettings::values.theme, + std::make_optional(std::string( + UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second))); + + SaveUIGamelistValues(); + SaveUILayoutValues(); + SavePathValues(); + SaveScreenshotValues(); + SaveShortcutValues(); + SaveMultiplayerValues(); + + EndGroup(); +} + +void QtConfig::SaveUIGamelistValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList)); + + WriteCategory(Settings::Category::UiGameList); + + BeginArray(std::string("favorites")); + for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) { + SetArrayIndex(i); + WriteSetting(std::string("program_id"), UISettings::values.favorited_ids[i]); + } + EndArray(); // favorites + + EndGroup(); +} + +void QtConfig::SaveUILayoutValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::UiLayout)); + + WriteCategory(Settings::Category::UiLayout); + + EndGroup(); +} + +void QtConfig::SaveMultiplayerValues() { + BeginGroup(std::string("Multiplayer")); + + WriteCategory(Settings::Category::Multiplayer); + + // Write ban list + BeginArray(std::string("username_ban_list")); + for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) { + SetArrayIndex(static_cast<int>(i)); + WriteSetting(std::string("username"), UISettings::values.multiplayer_ban_list.first[i]); + } + EndArray(); // username_ban_list + + BeginArray(std::string("ip_ban_list")); + for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) { + SetArrayIndex(static_cast<int>(i)); + WriteSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]); + } + EndArray(); // ip_ban_list + + EndGroup(); +} + +std::vector<Settings::BasicSetting*>& QtConfig::FindRelevantList(Settings::Category category) { + auto& map = Settings::values.linkage.by_category; + if (map.contains(category)) { + return Settings::values.linkage.by_category[category]; + } + return UISettings::values.linkage.by_category[category]; +} + +void QtConfig::ReadQtControlPlayerValues(std::size_t player_index) { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + ReadPlayerValues(player_index); + ReadQtPlayerValues(player_index); + + EndGroup(); +} + +void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + SavePlayerValues(player_index); + SaveQtPlayerValues(player_index); + + EndGroup(); + + WriteToIni(); +} diff --git a/src/yuzu/configuration/qt_config.h b/src/yuzu/configuration/qt_config.h new file mode 100644 index 000000000..dc2dceb4d --- /dev/null +++ b/src/yuzu/configuration/qt_config.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <QMetaType> + +#include "frontend_common/config.h" + +class QtConfig final : public Config { +public: + explicit QtConfig(const std::string& config_name = "qt-config", + ConfigType config_type = ConfigType::GlobalConfig); + ~QtConfig() override; + + void ReloadAllValues() override; + void SaveAllValues() override; + + void ReadQtControlPlayerValues(std::size_t player_index); + void SaveQtControlPlayerValues(std::size_t player_index); + +protected: + void ReadQtValues(); + void ReadQtPlayerValues(std::size_t player_index); + void ReadQtControlValues(); + void ReadHidbusValues() override; + void ReadDebugControlValues() override; + void ReadPathValues() override; + void ReadShortcutValues() override; + void ReadUIValues() override; + void ReadUIGamelistValues() override; + void ReadUILayoutValues() override; + void ReadMultiplayerValues() override; + + void SaveQtValues(); + void SaveQtPlayerValues(std::size_t player_index); + void SaveQtControlValues(); + void SaveHidbusValues() override; + void SaveDebugControlValues() override; + void SavePathValues() override; + void SaveShortcutValues() override; + void SaveUIValues() override; + void SaveUIGamelistValues() override; + void SaveUILayoutValues() override; + void SaveMultiplayerValues() override; + + std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override; + +public: + static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; + static const std::array<int, Settings::NativeMotion::NumMotions> default_motions; + static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; + static const std::array<int, 2> default_stick_mod; + static const std::array<int, 2> default_ringcon_analogs; +}; diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 1434b1a56..a7b5def32 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -1,17 +1,18 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/time_zone.h" #include "yuzu/configuration/shared_translation.h" #include <map> #include <memory> #include <tuple> #include <utility> +#include <QCoreApplication> #include <QWidget> #include "common/settings.h" #include "common/settings_enums.h" #include "common/settings_setting.h" +#include "common/time_zone.h" #include "yuzu/uisettings.h" namespace ConfigurationShared { @@ -21,123 +22,135 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; #define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ - translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{tr((NAME)), tr((TOOLTIP))}}) + translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}}) // A setting can be ignored by giving it a blank name // Audio - INSERT(Settings, sink_id, "Output Engine:", ""); - INSERT(Settings, audio_output_device_id, "Output Device:", ""); - INSERT(Settings, audio_input_device_id, "Input Device:", ""); - INSERT(Settings, audio_muted, "Mute audio", ""); - INSERT(Settings, volume, "Volume:", ""); - INSERT(Settings, dump_audio_commands, "", ""); - INSERT(UISettings, mute_when_in_background, "Mute audio when in background", ""); + INSERT(Settings, sink_id, tr("Output Engine:"), QStringLiteral()); + INSERT(Settings, audio_output_device_id, tr("Output Device:"), QStringLiteral()); + INSERT(Settings, audio_input_device_id, tr("Input Device:"), QStringLiteral()); + INSERT(Settings, audio_muted, tr("Mute audio"), QStringLiteral()); + INSERT(Settings, volume, tr("Volume:"), QStringLiteral()); + INSERT(Settings, dump_audio_commands, QStringLiteral(), QStringLiteral()); + INSERT(UISettings, mute_when_in_background, tr("Mute audio when in background"), + QStringLiteral()); // Core - INSERT(Settings, use_multi_core, "Multicore CPU Emulation", ""); - INSERT(Settings, memory_layout_mode, "Memory Layout", ""); - INSERT(Settings, use_speed_limit, "", ""); - INSERT(Settings, speed_limit, "Limit Speed Percent", ""); + INSERT(Settings, use_multi_core, tr("Multicore CPU Emulation"), QStringLiteral()); + INSERT(Settings, memory_layout_mode, tr("Memory Layout"), QStringLiteral()); + INSERT(Settings, use_speed_limit, QStringLiteral(), QStringLiteral()); + INSERT(Settings, speed_limit, tr("Limit Speed Percent"), QStringLiteral()); // Cpu - INSERT(Settings, cpu_accuracy, "Accuracy:", ""); + INSERT(Settings, cpu_accuracy, tr("Accuracy:"), QStringLiteral()); // Cpu Debug // Cpu Unsafe - INSERT(Settings, cpuopt_unsafe_unfuse_fma, - "Unfuse FMA (improve performance on CPUs without FMA)", - "This option improves speed by reducing accuracy of fused-multiply-add instructions on " - "CPUs without native FMA support."); - INSERT(Settings, cpuopt_unsafe_reduce_fp_error, "Faster FRSQRTE and FRECPE", - "This option improves the speed of some approximate floating-point functions by using " - "less accurate native approximations."); - INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, "Faster ASIMD instructions (32 bits only)", - "This option improves the speed of 32 bits ASIMD floating-point functions by running " - "with incorrect rounding modes."); - INSERT(Settings, cpuopt_unsafe_inaccurate_nan, "Inaccurate NaN handling", - "This option improves speed by removing NaN checking. Please note this also reduces " - "accuracy of certain floating-point instructions."); INSERT( - Settings, cpuopt_unsafe_fastmem_check, "Disable address space checks", - "This option improves speed by eliminating a safety check before every memory read/write " - "in guest. Disabling it may allow a game to read/write the emulator's memory."); - INSERT(Settings, cpuopt_unsafe_ignore_global_monitor, "Ignore global monitor", - "This option improves speed by relying only on the semantics of cmpxchg to ensure " + Settings, cpuopt_unsafe_unfuse_fma, + tr("Unfuse FMA (improve performance on CPUs without FMA)"), + tr("This option improves speed by reducing accuracy of fused-multiply-add instructions on " + "CPUs without native FMA support.")); + INSERT( + Settings, cpuopt_unsafe_reduce_fp_error, tr("Faster FRSQRTE and FRECPE"), + tr("This option improves the speed of some approximate floating-point functions by using " + "less accurate native approximations.")); + INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, + tr("Faster ASIMD instructions (32 bits only)"), + tr("This option improves the speed of 32 bits ASIMD floating-point functions by running " + "with incorrect rounding modes.")); + INSERT(Settings, cpuopt_unsafe_inaccurate_nan, tr("Inaccurate NaN handling"), + tr("This option improves speed by removing NaN checking. Please note this also reduces " + "accuracy of certain floating-point instructions.")); + INSERT(Settings, cpuopt_unsafe_fastmem_check, tr("Disable address space checks"), + tr("This option improves speed by eliminating a safety check before every memory " + "read/write " + "in guest. Disabling it may allow a game to read/write the emulator's memory.")); + INSERT( + Settings, cpuopt_unsafe_ignore_global_monitor, tr("Ignore global monitor"), + tr("This option improves speed by relying only on the semantics of cmpxchg to ensure " "safety of exclusive access instructions. Please note this may result in deadlocks and " - "other race conditions."); + "other race conditions.")); // Renderer - INSERT(Settings, renderer_backend, "API:", ""); - INSERT(Settings, vulkan_device, "Device:", ""); - INSERT(Settings, shader_backend, "Shader Backend:", ""); - INSERT(Settings, resolution_setup, "Resolution:", ""); - INSERT(Settings, scaling_filter, "Window Adapting Filter:", ""); - INSERT(Settings, fsr_sharpening_slider, "FSR Sharpness:", ""); - INSERT(Settings, anti_aliasing, "Anti-Aliasing Method:", ""); - INSERT(Settings, fullscreen_mode, "Fullscreen Mode:", ""); - INSERT(Settings, aspect_ratio, "Aspect Ratio:", ""); - INSERT(Settings, use_disk_shader_cache, "Use disk pipeline cache", ""); - INSERT(Settings, use_asynchronous_gpu_emulation, "Use asynchronous GPU emulation", ""); - INSERT(Settings, nvdec_emulation, "NVDEC emulation:", ""); - INSERT(Settings, accelerate_astc, "ASTC Decoding Method:", ""); - INSERT(Settings, astc_recompression, "ASTC Recompression Method:", ""); - INSERT(Settings, vsync_mode, "VSync Mode:", - "FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " + INSERT(Settings, renderer_backend, tr("API:"), QStringLiteral()); + INSERT(Settings, vulkan_device, tr("Device:"), QStringLiteral()); + INSERT(Settings, shader_backend, tr("Shader Backend:"), QStringLiteral()); + INSERT(Settings, resolution_setup, tr("Resolution:"), QStringLiteral()); + INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral()); + INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), QStringLiteral()); + INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), QStringLiteral()); + INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), QStringLiteral()); + INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"), QStringLiteral()); + INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"), QStringLiteral()); + INSERT(Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"), + QStringLiteral()); + INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"), QStringLiteral()); + INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"), QStringLiteral()); + INSERT(Settings, astc_recompression, tr("ASTC Recompression Method:"), QStringLiteral()); + INSERT( + Settings, vsync_mode, tr("VSync Mode:"), + tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " "refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from " "a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop " "frames.\nImmediate (no synchronization) just presents whatever is available and can " - "exhibit tearing."); - INSERT(Settings, bg_red, "", ""); - INSERT(Settings, bg_green, "", ""); - INSERT(Settings, bg_blue, "", ""); + "exhibit tearing.")); + INSERT(Settings, bg_red, QStringLiteral(), QStringLiteral()); + INSERT(Settings, bg_green, QStringLiteral(), QStringLiteral()); + INSERT(Settings, bg_blue, QStringLiteral(), QStringLiteral()); // Renderer (Advanced Graphics) - INSERT(Settings, async_presentation, "Enable asynchronous presentation (Vulkan only)", ""); - INSERT(Settings, renderer_force_max_clock, "Force maximum clocks (Vulkan only)", - "Runs work in the background while waiting for graphics commands to keep the GPU from " - "lowering its clock speed."); - INSERT(Settings, max_anisotropy, "Anisotropic Filtering:", ""); - INSERT(Settings, gpu_accuracy, "Accuracy Level:", ""); - INSERT(Settings, use_asynchronous_shaders, "Use asynchronous shader building (Hack)", - "Enables asynchronous shader compilation, which may reduce shader stutter. This feature " - "is experimental."); - INSERT(Settings, use_fast_gpu_time, "Use Fast GPU Time (Hack)", - "Enables Fast GPU Time. This option will force most games to run at their highest " - "native resolution."); - INSERT(Settings, use_vulkan_driver_pipeline_cache, "Use Vulkan pipeline cache", - "Enables GPU vendor-specific pipeline cache. This option can improve shader loading " - "time significantly in cases where the Vulkan driver does not store pipeline cache " - "files internally."); - INSERT(Settings, enable_compute_pipelines, "Enable Compute Pipelines (Intel Vulkan Only)", - "Enable compute pipelines, required by some games.\nThis setting only exists for Intel " + INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"), + QStringLiteral()); + INSERT( + Settings, renderer_force_max_clock, tr("Force maximum clocks (Vulkan only)"), + tr("Runs work in the background while waiting for graphics commands to keep the GPU from " + "lowering its clock speed.")); + INSERT(Settings, max_anisotropy, tr("Anisotropic Filtering:"), QStringLiteral()); + INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"), QStringLiteral()); + INSERT( + Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"), + tr("Enables asynchronous shader compilation, which may reduce shader stutter. This feature " + "is experimental.")); + INSERT(Settings, use_fast_gpu_time, tr("Use Fast GPU Time (Hack)"), + tr("Enables Fast GPU Time. This option will force most games to run at their highest " + "native resolution.")); + INSERT(Settings, use_vulkan_driver_pipeline_cache, tr("Use Vulkan pipeline cache"), + tr("Enables GPU vendor-specific pipeline cache. This option can improve shader loading " + "time significantly in cases where the Vulkan driver does not store pipeline cache " + "files internally.")); + INSERT( + Settings, enable_compute_pipelines, tr("Enable Compute Pipelines (Intel Vulkan Only)"), + tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel " "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled " - "on all other drivers."); - INSERT(Settings, use_reactive_flushing, "Enable Reactive Flushing", - "Uses reactive flushing instead of predictive flushing, allowing more accurate memory " - "syncing."); - INSERT(Settings, use_video_framerate, "Sync to framerate of video playback", - "Run the game at normal speed during video playback, even when the framerate is " - "unlocked."); - INSERT(Settings, barrier_feedback_loops, "Barrier feedback loops", - "Improves rendering of transparency effects in specific games."); + "on all other drivers.")); + INSERT( + Settings, use_reactive_flushing, tr("Enable Reactive Flushing"), + tr("Uses reactive flushing instead of predictive flushing, allowing more accurate memory " + "syncing.")); + INSERT(Settings, use_video_framerate, tr("Sync to framerate of video playback"), + tr("Run the game at normal speed during video playback, even when the framerate is " + "unlocked.")); + INSERT(Settings, barrier_feedback_loops, tr("Barrier feedback loops"), + tr("Improves rendering of transparency effects in specific games.")); // Renderer (Debug) // System - INSERT(Settings, rng_seed, "RNG Seed", ""); - INSERT(Settings, rng_seed_enabled, "", ""); - INSERT(Settings, device_name, "Device Name", ""); - INSERT(Settings, custom_rtc, "Custom RTC", ""); - INSERT(Settings, custom_rtc_enabled, "", ""); - INSERT(Settings, language_index, - "Language:", "Note: this can be overridden when region setting is auto-select"); - INSERT(Settings, region_index, "Region:", ""); - INSERT(Settings, time_zone_index, "Time Zone:", ""); - INSERT(Settings, sound_index, "Sound Output Mode:", ""); - INSERT(Settings, use_docked_mode, "Console Mode:", ""); - INSERT(Settings, current_user, "", ""); + INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral()); + INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral()); + INSERT(Settings, device_name, tr("Device Name"), QStringLiteral()); + INSERT(Settings, custom_rtc, tr("Custom RTC"), QStringLiteral()); + INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral()); + INSERT(Settings, language_index, tr("Language:"), + tr("Note: this can be overridden when region setting is auto-select")); + INSERT(Settings, region_index, tr("Region:"), QStringLiteral()); + INSERT(Settings, time_zone_index, tr("Time Zone:"), QStringLiteral()); + INSERT(Settings, sound_index, tr("Sound Output Mode:"), QStringLiteral()); + INSERT(Settings, use_docked_mode, tr("Console Mode:"), QStringLiteral()); + INSERT(Settings, current_user, QStringLiteral(), QStringLiteral()); // Controls @@ -154,11 +167,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { // Ui // Ui General - INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); - INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); - INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); - INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); - INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); + INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"), QStringLiteral()); + INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"), + QStringLiteral()); + INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"), + QStringLiteral()); + INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), QStringLiteral()); + INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"), + QStringLiteral()); // Ui Debugging @@ -178,140 +194,141 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) { return parent->tr(text, context); }; -#define PAIR(ENUM, VALUE, TRANSLATION) \ - { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION) } -#define CTX_PAIR(ENUM, VALUE, TRANSLATION, CONTEXT) \ - { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION, CONTEXT) } +#define PAIR(ENUM, VALUE, TRANSLATION) {static_cast<u32>(Settings::ENUM::VALUE), (TRANSLATION)} // Intentionally skipping VSyncMode to let the UI fill that one out translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(), { - PAIR(AstcDecodeMode, Cpu, "CPU"), - PAIR(AstcDecodeMode, Gpu, "GPU"), - PAIR(AstcDecodeMode, CpuAsynchronous, "CPU Asynchronous"), - }}); - translations->insert({Settings::EnumMetadata<Settings::AstcRecompression>::Index(), - { - PAIR(AstcRecompression, Uncompressed, "Uncompressed (Best quality)"), - PAIR(AstcRecompression, Bc1, "BC1 (Low quality)"), - PAIR(AstcRecompression, Bc3, "BC3 (Medium quality)"), + PAIR(AstcDecodeMode, Cpu, tr("CPU")), + PAIR(AstcDecodeMode, Gpu, tr("GPU")), + PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")), }}); + translations->insert( + {Settings::EnumMetadata<Settings::AstcRecompression>::Index(), + { + PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")), + PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")), + PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")), + }}); translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(), { #ifdef HAS_OPENGL - PAIR(RendererBackend, OpenGL, "OpenGL"), + PAIR(RendererBackend, OpenGL, tr("OpenGL")), #endif - PAIR(RendererBackend, Vulkan, "Vulkan"), - PAIR(RendererBackend, Null, "Null"), - }}); - translations->insert({Settings::EnumMetadata<Settings::ShaderBackend>::Index(), - { - PAIR(ShaderBackend, Glsl, "GLSL"), - PAIR(ShaderBackend, Glasm, "GLASM (Assembly Shaders, NVIDIA Only)"), - PAIR(ShaderBackend, SpirV, "SPIR-V (Experimental, Mesa Only)"), + PAIR(RendererBackend, Vulkan, tr("Vulkan")), + PAIR(RendererBackend, Null, tr("Null")), }}); + translations->insert( + {Settings::EnumMetadata<Settings::ShaderBackend>::Index(), + { + PAIR(ShaderBackend, Glsl, tr("GLSL")), + PAIR(ShaderBackend, Glasm, tr("GLASM (Assembly Shaders, NVIDIA Only)")), + PAIR(ShaderBackend, SpirV, tr("SPIR-V (Experimental, Mesa Only)")), + }}); translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(), { - PAIR(GpuAccuracy, Normal, "Normal"), - PAIR(GpuAccuracy, High, "High"), - PAIR(GpuAccuracy, Extreme, "Extreme"), - }}); - translations->insert({Settings::EnumMetadata<Settings::CpuAccuracy>::Index(), - { - PAIR(CpuAccuracy, Auto, "Auto"), - PAIR(CpuAccuracy, Accurate, "Accurate"), - PAIR(CpuAccuracy, Unsafe, "Unsafe"), - PAIR(CpuAccuracy, Paranoid, "Paranoid (disables most optimizations)"), + PAIR(GpuAccuracy, Normal, tr("Normal")), + PAIR(GpuAccuracy, High, tr("High")), + PAIR(GpuAccuracy, Extreme, tr("Extreme")), }}); + translations->insert( + {Settings::EnumMetadata<Settings::CpuAccuracy>::Index(), + { + PAIR(CpuAccuracy, Auto, tr("Auto")), + PAIR(CpuAccuracy, Accurate, tr("Accurate")), + PAIR(CpuAccuracy, Unsafe, tr("Unsafe")), + PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")), + }}); translations->insert({Settings::EnumMetadata<Settings::FullscreenMode>::Index(), { - PAIR(FullscreenMode, Borderless, "Borderless Windowed"), - PAIR(FullscreenMode, Exclusive, "Exclusive Fullscreen"), + PAIR(FullscreenMode, Borderless, tr("Borderless Windowed")), + PAIR(FullscreenMode, Exclusive, tr("Exclusive Fullscreen")), }}); translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(), { - PAIR(NvdecEmulation, Off, "No Video Output"), - PAIR(NvdecEmulation, Cpu, "CPU Video Decoding"), - PAIR(NvdecEmulation, Gpu, "GPU Video Decoding (Default)"), - }}); - translations->insert({Settings::EnumMetadata<Settings::ResolutionSetup>::Index(), - { - PAIR(ResolutionSetup, Res1_2X, "0.5X (360p/540p) [EXPERIMENTAL]"), - PAIR(ResolutionSetup, Res3_4X, "0.75X (540p/810p) [EXPERIMENTAL]"), - PAIR(ResolutionSetup, Res1X, "1X (720p/1080p)"), - PAIR(ResolutionSetup, Res3_2X, "1.5X (1080p/1620p) [EXPERIMENTAL]"), - PAIR(ResolutionSetup, Res2X, "2X (1440p/2160p)"), - PAIR(ResolutionSetup, Res3X, "3X (2160p/3240p)"), - PAIR(ResolutionSetup, Res4X, "4X (2880p/4320p)"), - PAIR(ResolutionSetup, Res5X, "5X (3600p/5400p)"), - PAIR(ResolutionSetup, Res6X, "6X (4320p/6480p)"), - PAIR(ResolutionSetup, Res7X, "7X (5040p/7560p)"), - PAIR(ResolutionSetup, Res8X, "8X (5760p/8640p)"), + PAIR(NvdecEmulation, Off, tr("No Video Output")), + PAIR(NvdecEmulation, Cpu, tr("CPU Video Decoding")), + PAIR(NvdecEmulation, Gpu, tr("GPU Video Decoding (Default)")), }}); + translations->insert( + {Settings::EnumMetadata<Settings::ResolutionSetup>::Index(), + { + PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")), + PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")), + PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")), + PAIR(ResolutionSetup, Res3_2X, tr("1.5X (1080p/1620p) [EXPERIMENTAL]")), + PAIR(ResolutionSetup, Res2X, tr("2X (1440p/2160p)")), + PAIR(ResolutionSetup, Res3X, tr("3X (2160p/3240p)")), + PAIR(ResolutionSetup, Res4X, tr("4X (2880p/4320p)")), + PAIR(ResolutionSetup, Res5X, tr("5X (3600p/5400p)")), + PAIR(ResolutionSetup, Res6X, tr("6X (4320p/6480p)")), + PAIR(ResolutionSetup, Res7X, tr("7X (5040p/7560p)")), + PAIR(ResolutionSetup, Res8X, tr("8X (5760p/8640p)")), + }}); translations->insert({Settings::EnumMetadata<Settings::ScalingFilter>::Index(), { - PAIR(ScalingFilter, NearestNeighbor, "Nearest Neighbor"), - PAIR(ScalingFilter, Bilinear, "Bilinear"), - PAIR(ScalingFilter, Bicubic, "Bicubic"), - PAIR(ScalingFilter, Gaussian, "Gaussian"), - PAIR(ScalingFilter, ScaleForce, "ScaleForce"), - PAIR(ScalingFilter, Fsr, "AMD FidelityFX™️ Super Resolution"), + PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")), + PAIR(ScalingFilter, Bilinear, tr("Bilinear")), + PAIR(ScalingFilter, Bicubic, tr("Bicubic")), + PAIR(ScalingFilter, Gaussian, tr("Gaussian")), + PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")), + PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")), }}); translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(), { - PAIR(AntiAliasing, None, "None"), - PAIR(AntiAliasing, Fxaa, "FXAA"), - PAIR(AntiAliasing, Smaa, "SMAA"), + PAIR(AntiAliasing, None, tr("None")), + PAIR(AntiAliasing, Fxaa, tr("FXAA")), + PAIR(AntiAliasing, Smaa, tr("SMAA")), }}); translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(), { - PAIR(AspectRatio, R16_9, "Default (16:9)"), - PAIR(AspectRatio, R4_3, "Force 4:3"), - PAIR(AspectRatio, R21_9, "Force 21:9"), - PAIR(AspectRatio, R16_10, "Force 16:10"), - PAIR(AspectRatio, Stretch, "Stretch to Window"), + PAIR(AspectRatio, R16_9, tr("Default (16:9)")), + PAIR(AspectRatio, R4_3, tr("Force 4:3")), + PAIR(AspectRatio, R21_9, tr("Force 21:9")), + PAIR(AspectRatio, R16_10, tr("Force 16:10")), + PAIR(AspectRatio, Stretch, tr("Stretch to Window")), }}); translations->insert({Settings::EnumMetadata<Settings::AnisotropyMode>::Index(), { - PAIR(AnisotropyMode, Automatic, "Automatic"), - PAIR(AnisotropyMode, Default, "Default"), - PAIR(AnisotropyMode, X2, "2x"), - PAIR(AnisotropyMode, X4, "4x"), - PAIR(AnisotropyMode, X8, "8x"), - PAIR(AnisotropyMode, X16, "16x"), + PAIR(AnisotropyMode, Automatic, tr("Automatic")), + PAIR(AnisotropyMode, Default, tr("Default")), + PAIR(AnisotropyMode, X2, tr("2x")), + PAIR(AnisotropyMode, X4, tr("4x")), + PAIR(AnisotropyMode, X8, tr("8x")), + PAIR(AnisotropyMode, X16, tr("16x")), }}); translations->insert( {Settings::EnumMetadata<Settings::Language>::Index(), { - PAIR(Language, Japanese, "Japanese (日本語)"), - PAIR(Language, EnglishAmerican, "American English"), - PAIR(Language, French, "French (français)"), - PAIR(Language, German, "German (Deutsch)"), - PAIR(Language, Italian, "Italian (italiano)"), - PAIR(Language, Spanish, "Spanish (español)"), - PAIR(Language, Chinese, "Chinese"), - PAIR(Language, Korean, "Korean (한국어)"), - PAIR(Language, Dutch, "Dutch (Nederlands)"), - PAIR(Language, Portuguese, "Portuguese (português)"), - PAIR(Language, Russian, "Russian (Русский)"), - PAIR(Language, Taiwanese, "Taiwanese"), - PAIR(Language, EnglishBritish, "British English"), - PAIR(Language, FrenchCanadian, "Canadian French"), - PAIR(Language, SpanishLatin, "Latin American Spanish"), - PAIR(Language, ChineseSimplified, "Simplified Chinese"), - PAIR(Language, ChineseTraditional, "Traditional Chinese (正體中文)"), - PAIR(Language, PortugueseBrazilian, "Brazilian Portuguese (português do Brasil)"), + PAIR(Language, Japanese, tr("Japanese (日本語)")), + PAIR(Language, EnglishAmerican, tr("American English")), + PAIR(Language, French, tr("French (français)")), + PAIR(Language, German, tr("German (Deutsch)")), + PAIR(Language, Italian, tr("Italian (italiano)")), + PAIR(Language, Spanish, tr("Spanish (español)")), + PAIR(Language, Chinese, tr("Chinese")), + PAIR(Language, Korean, tr("Korean (한국어)")), + PAIR(Language, Dutch, tr("Dutch (Nederlands)")), + PAIR(Language, Portuguese, tr("Portuguese (português)")), + PAIR(Language, Russian, tr("Russian (Русский)")), + PAIR(Language, Taiwanese, tr("Taiwanese")), + PAIR(Language, EnglishBritish, tr("British English")), + PAIR(Language, FrenchCanadian, tr("Canadian French")), + PAIR(Language, SpanishLatin, tr("Latin American Spanish")), + PAIR(Language, ChineseSimplified, tr("Simplified Chinese")), + PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")), + PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")), }}); translations->insert({Settings::EnumMetadata<Settings::Region>::Index(), { - PAIR(Region, Japan, "Japan"), - PAIR(Region, Usa, "USA"), - PAIR(Region, Europe, "Europe"), - PAIR(Region, Australia, "Australia"), - PAIR(Region, China, "China"), - PAIR(Region, Korea, "Korea"), - PAIR(Region, Taiwan, "Taiwan"), + PAIR(Region, Japan, tr("Japan")), + PAIR(Region, Usa, tr("USA")), + PAIR(Region, Europe, tr("Europe")), + PAIR(Region, Australia, tr("Australia")), + PAIR(Region, China, tr("China")), + PAIR(Region, Korea, tr("Korea")), + PAIR(Region, Taiwan, tr("Taiwan")), }}); translations->insert( {Settings::EnumMetadata<Settings::TimeZone>::Index(), @@ -323,72 +340,74 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) { {static_cast<u32>(Settings::TimeZone::Default), tr("Default (%1)", "Default time zone") .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, - PAIR(TimeZone, Cet, "CET"), - PAIR(TimeZone, Cst6Cdt, "CST6CDT"), - PAIR(TimeZone, Cuba, "Cuba"), - PAIR(TimeZone, Eet, "EET"), - PAIR(TimeZone, Egypt, "Egypt"), - PAIR(TimeZone, Eire, "Eire"), - PAIR(TimeZone, Est, "EST"), - PAIR(TimeZone, Est5Edt, "EST5EDT"), - PAIR(TimeZone, Gb, "GB"), - PAIR(TimeZone, GbEire, "GB-Eire"), - PAIR(TimeZone, Gmt, "GMT"), - PAIR(TimeZone, GmtPlusZero, "GMT+0"), - PAIR(TimeZone, GmtMinusZero, "GMT-0"), - PAIR(TimeZone, GmtZero, "GMT0"), - PAIR(TimeZone, Greenwich, "Greenwich"), - PAIR(TimeZone, Hongkong, "Hongkong"), - PAIR(TimeZone, Hst, "HST"), - PAIR(TimeZone, Iceland, "Iceland"), - PAIR(TimeZone, Iran, "Iran"), - PAIR(TimeZone, Israel, "Israel"), - PAIR(TimeZone, Jamaica, "Jamaica"), - PAIR(TimeZone, Japan, "Japan"), - PAIR(TimeZone, Kwajalein, "Kwajalein"), - PAIR(TimeZone, Libya, "Libya"), - PAIR(TimeZone, Met, "MET"), - PAIR(TimeZone, Mst, "MST"), - PAIR(TimeZone, Mst7Mdt, "MST7MDT"), - PAIR(TimeZone, Navajo, "Navajo"), - PAIR(TimeZone, Nz, "NZ"), - PAIR(TimeZone, NzChat, "NZ-CHAT"), - PAIR(TimeZone, Poland, "Poland"), - PAIR(TimeZone, Portugal, "Portugal"), - PAIR(TimeZone, Prc, "PRC"), - PAIR(TimeZone, Pst8Pdt, "PST8PDT"), - PAIR(TimeZone, Roc, "ROC"), - PAIR(TimeZone, Rok, "ROK"), - PAIR(TimeZone, Singapore, "Singapore"), - PAIR(TimeZone, Turkey, "Turkey"), - PAIR(TimeZone, Uct, "UCT"), - PAIR(TimeZone, Universal, "Universal"), - PAIR(TimeZone, Utc, "UTC"), - PAIR(TimeZone, WSu, "W-SU"), - PAIR(TimeZone, Wet, "WET"), - PAIR(TimeZone, Zulu, "Zulu"), + PAIR(TimeZone, Cet, tr("CET")), + PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")), + PAIR(TimeZone, Cuba, tr("Cuba")), + PAIR(TimeZone, Eet, tr("EET")), + PAIR(TimeZone, Egypt, tr("Egypt")), + PAIR(TimeZone, Eire, tr("Eire")), + PAIR(TimeZone, Est, tr("EST")), + PAIR(TimeZone, Est5Edt, tr("EST5EDT")), + PAIR(TimeZone, Gb, tr("GB")), + PAIR(TimeZone, GbEire, tr("GB-Eire")), + PAIR(TimeZone, Gmt, tr("GMT")), + PAIR(TimeZone, GmtPlusZero, tr("GMT+0")), + PAIR(TimeZone, GmtMinusZero, tr("GMT-0")), + PAIR(TimeZone, GmtZero, tr("GMT0")), + PAIR(TimeZone, Greenwich, tr("Greenwich")), + PAIR(TimeZone, Hongkong, tr("Hongkong")), + PAIR(TimeZone, Hst, tr("HST")), + PAIR(TimeZone, Iceland, tr("Iceland")), + PAIR(TimeZone, Iran, tr("Iran")), + PAIR(TimeZone, Israel, tr("Israel")), + PAIR(TimeZone, Jamaica, tr("Jamaica")), + PAIR(TimeZone, Japan, tr("Japan")), + PAIR(TimeZone, Kwajalein, tr("Kwajalein")), + PAIR(TimeZone, Libya, tr("Libya")), + PAIR(TimeZone, Met, tr("MET")), + PAIR(TimeZone, Mst, tr("MST")), + PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")), + PAIR(TimeZone, Navajo, tr("Navajo")), + PAIR(TimeZone, Nz, tr("NZ")), + PAIR(TimeZone, NzChat, tr("NZ-CHAT")), + PAIR(TimeZone, Poland, tr("Poland")), + PAIR(TimeZone, Portugal, tr("Portugal")), + PAIR(TimeZone, Prc, tr("PRC")), + PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")), + PAIR(TimeZone, Roc, tr("ROC")), + PAIR(TimeZone, Rok, tr("ROK")), + PAIR(TimeZone, Singapore, tr("Singapore")), + PAIR(TimeZone, Turkey, tr("Turkey")), + PAIR(TimeZone, Uct, tr("UCT")), + PAIR(TimeZone, Universal, tr("Universal")), + PAIR(TimeZone, Utc, tr("UTC")), + PAIR(TimeZone, WSu, tr("W-SU")), + PAIR(TimeZone, Wet, tr("WET")), + PAIR(TimeZone, Zulu, tr("Zulu")), }}); translations->insert({Settings::EnumMetadata<Settings::AudioMode>::Index(), { - PAIR(AudioMode, Mono, "Mono"), - PAIR(AudioMode, Stereo, "Stereo"), - PAIR(AudioMode, Surround, "Surround"), + PAIR(AudioMode, Mono, tr("Mono")), + PAIR(AudioMode, Stereo, tr("Stereo")), + PAIR(AudioMode, Surround, tr("Surround")), }}); translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(), { - PAIR(MemoryLayout, Memory_4Gb, "4GB DRAM (Default)"), - PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"), - PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"), + PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")), + PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")), + PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM (Unsafe)")), + }}); + translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(), + { + PAIR(ConsoleMode, Docked, tr("Docked")), + PAIR(ConsoleMode, Handheld, tr("Handheld")), }}); - translations->insert( - {Settings::EnumMetadata<Settings::ConsoleMode>::Index(), - {PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}}); translations->insert( {Settings::EnumMetadata<Settings::ConfirmStop>::Index(), { - PAIR(ConfirmStop, Ask_Always, "Always ask (Default)"), - PAIR(ConfirmStop, Ask_Based_On_Game, "Only if game specifies not to stop"), - PAIR(ConfirmStop, Ask_Never, "Never ask"), + PAIR(ConfirmStop, Ask_Always, tr("Always ask (Default)")), + PAIR(ConfirmStop, Ask_Based_On_Game, tr("Only if game specifies not to stop")), + PAIR(ConfirmStop, Ask_Never, tr("Never ask")), }}); #undef PAIR diff --git a/src/yuzu/configuration/shared_translation.h b/src/yuzu/configuration/shared_translation.h index 99a0e808c..d5fc3b8de 100644 --- a/src/yuzu/configuration/shared_translation.h +++ b/src/yuzu/configuration/shared_translation.h @@ -10,6 +10,7 @@ #include <vector> #include <QString> #include "common/common_types.h" +#include "common/settings.h" class QWidget; @@ -22,4 +23,46 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent); std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent); +static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map = { + {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))}, + {Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))}, + {Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))}, +}; + +static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map = { + {Settings::ScalingFilter::NearestNeighbor, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))}, + {Settings::ScalingFilter::Bilinear, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))}, + {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))}, + {Settings::ScalingFilter::Gaussian, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))}, + {Settings::ScalingFilter::ScaleForce, + QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))}, + {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))}, +}; + +static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = { + {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))}, + {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))}, +}; + +static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = { + {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))}, + {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))}, + {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))}, +}; + +static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map = { + {Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))}, + {Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))}, + {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))}, +}; + +static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map = { + {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))}, + {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))}, + {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))}, +}; + } // namespace ConfigurationShared diff --git a/src/yuzu/configuration/shared_widget.cpp b/src/yuzu/configuration/shared_widget.cpp index ea8d7add4..941683a43 100644 --- a/src/yuzu/configuration/shared_widget.cpp +++ b/src/yuzu/configuration/shared_widget.cpp @@ -194,7 +194,7 @@ QWidget* Widget::CreateRadioGroup(std::function<std::string()>& serializer, return group; } - const auto get_selected = [=]() -> int { + const auto get_selected = [this]() -> int { for (const auto& [id, button] : radio_buttons) { if (button->isChecked()) { return id; @@ -203,7 +203,7 @@ QWidget* Widget::CreateRadioGroup(std::function<std::string()>& serializer, return -1; }; - const auto set_index = [=](u32 value) { + const auto set_index = [this](u32 value) { for (const auto& [id, button] : radio_buttons) { button->setChecked(id == value); } diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 7049c57b6..6d227ef8d 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -36,10 +36,8 @@ constexpr std::array<std::array<Qt::GlobalColor, 2>, 10> WaitTreeColors{{ bool IsDarkTheme() { const auto& theme = UISettings::values.theme; - return theme == QStringLiteral("qdarkstyle") || - theme == QStringLiteral("qdarkstyle_midnight_blue") || - theme == QStringLiteral("colorful_dark") || - theme == QStringLiteral("colorful_midnight_blue"); + return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") || + theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue"); } } // namespace diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index f294dc23d..59b317135 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -278,7 +278,7 @@ void GameList::OnUpdateThemedIcons() { case GameListItemType::CustomDir: { const UISettings::GameDir& game_dir = UISettings::values.game_dirs[child->data(GameListDir::GameDirRole).toInt()]; - const QString icon_name = QFileInfo::exists(game_dir.path) + const QString icon_name = QFileInfo::exists(QString::fromStdString(game_dir.path)) ? QStringLiteral("folder") : QStringLiteral("bad_folder"); child->setData( @@ -727,7 +727,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) { }); connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { - emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path); + emit OpenDirectory( + QString::fromStdString(UISettings::values.game_dirs[game_dir_index].path)); }); } @@ -869,7 +870,7 @@ const QStringList GameList::supported_file_extensions = { QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; void GameList::RefreshGameDirectory() { - if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) { + if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); PopulateAsync(UISettings::values.game_dirs); } diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 86a0c41d9..c330b574f 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -286,13 +286,13 @@ public: setData(QObject::tr("System Titles"), Qt::DisplayRole); break; case GameListItemType::CustomDir: { - const QString icon_name = QFileInfo::exists(game_dir->path) - ? QStringLiteral("folder") - : QStringLiteral("bad_folder"); + const QString path = QString::fromStdString(game_dir->path); + const QString icon_name = + QFileInfo::exists(path) ? QStringLiteral("folder") : QStringLiteral("bad_folder"); setData(QIcon::fromTheme(icon_name).pixmap(icon_size).scaled( icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::DecorationRole); - setData(game_dir->path, Qt::DisplayRole); + setData(path, Qt::DisplayRole); break; } default: diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 69be21027..dc006832e 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -456,29 +456,29 @@ void GameListWorker::run() { break; } - if (game_dir.path == QStringLiteral("SDMC")) { + if (game_dir.path == std::string("SDMC")) { auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SdmcDir); DirEntryReady(game_list_dir); AddTitlesToGameList(game_list_dir); - } else if (game_dir.path == QStringLiteral("UserNAND")) { + } else if (game_dir.path == std::string("UserNAND")) { auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::UserNandDir); DirEntryReady(game_list_dir); AddTitlesToGameList(game_list_dir); - } else if (game_dir.path == QStringLiteral("SysNAND")) { + } else if (game_dir.path == std::string("SysNAND")) { auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SysNandDir); DirEntryReady(game_list_dir); AddTitlesToGameList(game_list_dir); } else { - watch_list.append(game_dir.path); + watch_list.append(QString::fromStdString(game_dir.path)); auto* const game_list_dir = new GameListDir(game_dir); DirEntryReady(game_list_dir); - ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), - game_dir.deep_scan, game_list_dir); - ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), - game_dir.deep_scan, game_list_dir); + ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path, game_dir.deep_scan, + game_list_dir); + ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path, game_dir.deep_scan, + game_list_dir); } } - RecordEvent([=](GameList* game_list) { game_list->DonePopulating(watch_list); }); + RecordEvent([this](GameList* game_list) { game_list->DonePopulating(watch_list); }); processing_completed.Set(); } diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index 6530186c1..eebfbf155 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -19,7 +19,7 @@ void HotkeyRegistry::SaveHotkeys() { for (const auto& hotkey : group.second) { UISettings::values.shortcuts.push_back( {hotkey.first, group.first, - UISettings::ContextualShortcut({hotkey.second.keyseq.toString(), + UISettings::ContextualShortcut({hotkey.second.keyseq.toString().toStdString(), hotkey.second.controller_keyseq, hotkey.second.context, hotkey.second.repeat})}); } @@ -31,12 +31,12 @@ void HotkeyRegistry::LoadHotkeys() { // beginGroup() for (auto shortcut : UISettings::values.shortcuts) { Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name]; - if (!shortcut.shortcut.keyseq.isEmpty()) { - hk.keyseq = - QKeySequence::fromString(shortcut.shortcut.keyseq, QKeySequence::NativeText); + if (!shortcut.shortcut.keyseq.empty()) { + hk.keyseq = QKeySequence::fromString(QString::fromStdString(shortcut.shortcut.keyseq), + QKeySequence::NativeText); hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.context); } - if (!shortcut.shortcut.controller_keyseq.isEmpty()) { + if (!shortcut.shortcut.controller_keyseq.empty()) { hk.controller_keyseq = shortcut.shortcut.controller_keyseq; } if (hk.shortcut) { @@ -51,7 +51,8 @@ void HotkeyRegistry::LoadHotkeys() { } } -QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { +QShortcut* HotkeyRegistry::GetHotkey(const std::string& group, const std::string& action, + QWidget* widget) { Hotkey& hk = hotkey_groups[group][action]; if (!hk.shortcut) { @@ -62,7 +63,8 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action return hk.shortcut; } -ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const QString& group, const QString& action, +ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const std::string& group, + const std::string& action, Core::HID::EmulatedController* controller) { Hotkey& hk = hotkey_groups[group][action]; @@ -74,12 +76,12 @@ ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const QString& group, co return hk.controller_shortcut; } -QKeySequence HotkeyRegistry::GetKeySequence(const QString& group, const QString& action) { +QKeySequence HotkeyRegistry::GetKeySequence(const std::string& group, const std::string& action) { return hotkey_groups[group][action].keyseq; } -Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const QString& group, - const QString& action) { +Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const std::string& group, + const std::string& action) { return hotkey_groups[group][action].context; } @@ -101,10 +103,10 @@ void ControllerShortcut::SetKey(const ControllerButtonSequence& buttons) { button_sequence = buttons; } -void ControllerShortcut::SetKey(const QString& buttons_shortcut) { +void ControllerShortcut::SetKey(const std::string& buttons_shortcut) { ControllerButtonSequence sequence{}; - name = buttons_shortcut.toStdString(); - std::istringstream command_line(buttons_shortcut.toStdString()); + name = buttons_shortcut; + std::istringstream command_line(buttons_shortcut); std::string line; while (std::getline(command_line, line, '+')) { if (line.empty()) { diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h index 56eee8d82..e11332d2e 100644 --- a/src/yuzu/hotkeys.h +++ b/src/yuzu/hotkeys.h @@ -33,7 +33,7 @@ public: ~ControllerShortcut(); void SetKey(const ControllerButtonSequence& buttons); - void SetKey(const QString& buttons_shortcut); + void SetKey(const std::string& buttons_shortcut); ControllerButtonSequence ButtonSequence() const; @@ -88,8 +88,8 @@ public: * will be the same. Thus, you shouldn't rely on the caller really being the * QShortcut's parent. */ - QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); - ControllerShortcut* GetControllerHotkey(const QString& group, const QString& action, + QShortcut* GetHotkey(const std::string& group, const std::string& action, QWidget* widget); + ControllerShortcut* GetControllerHotkey(const std::string& group, const std::string& action, Core::HID::EmulatedController* controller); /** @@ -98,7 +98,7 @@ public: * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger"). * @param action Name of the action (e.g. "Start Emulation", "Load Image"). */ - QKeySequence GetKeySequence(const QString& group, const QString& action); + QKeySequence GetKeySequence(const std::string& group, const std::string& action); /** * Returns a Qt::ShortcutContext object who can be connected to other @@ -108,20 +108,20 @@ public: * "Debugger"). * @param action Name of the action (e.g. "Start Emulation", "Load Image"). */ - Qt::ShortcutContext GetShortcutContext(const QString& group, const QString& action); + Qt::ShortcutContext GetShortcutContext(const std::string& group, const std::string& action); private: struct Hotkey { QKeySequence keyseq; - QString controller_keyseq; + std::string controller_keyseq; QShortcut* shortcut = nullptr; ControllerShortcut* controller_shortcut = nullptr; Qt::ShortcutContext context = Qt::WindowShortcut; bool repeat; }; - using HotkeyMap = std::map<QString, Hotkey>; - using HotkeyGroupMap = std::map<QString, HotkeyMap>; + using HotkeyMap = std::map<std::string, Hotkey>; + using HotkeyGroupMap = std::map<std::string, HotkeyMap>; HotkeyGroupMap hotkey_groups; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f22db233b..defe45198 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -128,6 +128,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/loader/loader.h" #include "core/perf_stats.h" #include "core/telemetry_session.h" +#include "frontend_common/config.h" #include "input_common/drivers/tas_input.h" #include "input_common/drivers/virtual_amiibo.h" #include "input_common/main.h" @@ -140,9 +141,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/bootmanager.h" #include "yuzu/compatdb.h" #include "yuzu/compatibility_list.h" -#include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_dialog.h" #include "yuzu/configuration/configure_input_per_game.h" +#include "yuzu/configuration/qt_config.h" #include "yuzu/debugger/console.h" #include "yuzu/debugger/controller.h" #include "yuzu/debugger/profiler.h" @@ -311,7 +312,7 @@ bool GMainWindow::CheckDarkMode() { #endif // __unix__ } -GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan) +GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan) : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)}, vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, @@ -676,7 +677,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers( // Don't forget to apply settings. system->HIDCore().DisableAllControllerConfiguration(); system->ApplySettings(); - config->Save(); + config->SaveAllValues(); UpdateStatusButtons(); @@ -1129,7 +1130,7 @@ void GMainWindow::InitializeWidgets() { connect(aa_status_button, &QPushButton::customContextMenuRequested, [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& aa_text_pair : Config::anti_aliasing_texts_map) { + for (auto const& aa_text_pair : ConfigurationShared::anti_aliasing_texts_map) { context_menu.addAction(aa_text_pair.second, [this, aa_text_pair] { Settings::values.anti_aliasing.SetValue(aa_text_pair.first); UpdateAAText(); @@ -1153,7 +1154,7 @@ void GMainWindow::InitializeWidgets() { connect(filter_status_button, &QPushButton::customContextMenuRequested, [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& filter_text_pair : Config::scaling_filter_texts_map) { + for (auto const& filter_text_pair : ConfigurationShared::scaling_filter_texts_map) { context_menu.addAction(filter_text_pair.second, [this, filter_text_pair] { Settings::values.scaling_filter.SetValue(filter_text_pair.first); UpdateFilterText(); @@ -1176,7 +1177,7 @@ void GMainWindow::InitializeWidgets() { [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& pair : Config::use_docked_mode_texts_map) { + for (auto const& pair : ConfigurationShared::use_docked_mode_texts_map) { context_menu.addAction(pair.second, [this, &pair] { if (pair.first != Settings::values.use_docked_mode.GetValue()) { OnToggleDockedMode(); @@ -1200,7 +1201,7 @@ void GMainWindow::InitializeWidgets() { [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& gpu_accuracy_pair : Config::gpu_accuracy_texts_map) { + for (auto const& gpu_accuracy_pair : ConfigurationShared::gpu_accuracy_texts_map) { if (gpu_accuracy_pair.first == Settings::GpuAccuracy::Extreme) { continue; } @@ -1229,7 +1230,8 @@ void GMainWindow::InitializeWidgets() { [this](const QPoint& menu_location) { QMenu context_menu; - for (auto const& renderer_backend_pair : Config::renderer_backend_texts_map) { + for (auto const& renderer_backend_pair : + ConfigurationShared::renderer_backend_texts_map) { if (renderer_backend_pair.first == Settings::RendererBackend::Null) { continue; } @@ -1294,16 +1296,17 @@ void GMainWindow::InitializeRecentFileMenuActions() { void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name, const bool tas_allowed) { - static const QString main_window = QStringLiteral("Main Window"); - action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name)); - action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name)); + static const auto main_window = std::string("Main Window"); + action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name.toStdString())); + action->setShortcutContext( + hotkey_registry.GetShortcutContext(main_window, action_name.toStdString())); action->setAutoRepeat(false); this->addAction(action); auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); const auto* controller_hotkey = - hotkey_registry.GetControllerHotkey(main_window, action_name, controller); + hotkey_registry.GetControllerHotkey(main_window, action_name.toStdString(), controller); connect( controller_hotkey, &ControllerShortcut::Activated, this, [action, tas_allowed, this] { @@ -1335,10 +1338,11 @@ void GMainWindow::InitializeHotkeys() { static const QString main_window = QStringLiteral("Main Window"); const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) { - const auto* hotkey = hotkey_registry.GetHotkey(main_window, action_name, this); + const auto* hotkey = + hotkey_registry.GetHotkey(main_window.toStdString(), action_name.toStdString(), this); auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - const auto* controller_hotkey = - hotkey_registry.GetControllerHotkey(main_window, action_name, controller); + const auto* controller_hotkey = hotkey_registry.GetControllerHotkey( + main_window.toStdString(), action_name.toStdString(), controller); connect(hotkey, &QShortcut::activated, this, function); connect(controller_hotkey, &ControllerShortcut::Activated, this, function, Qt::QueuedConnection); @@ -1918,7 +1922,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t // Save configurations UpdateUISettings(); game_list->SaveInterfaceLayout(); - config->Save(); + config->SaveAllValues(); u64 title_id{0}; @@ -1936,7 +1940,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) : fmt::format("{:016X}", title_id); - Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); + QtConfig per_game_config(config_file_name, Config::ConfigType::PerGameConfig); system->HIDCore().ReloadInputDevices(); system->ApplySettings(); } @@ -3135,7 +3139,7 @@ void GMainWindow::OnGameListAddDirectory() { return; } - UISettings::GameDir game_dir{dir_path, false, true}; + UISettings::GameDir game_dir{dir_path.toStdString(), false, true}; if (!UISettings::values.game_dirs.contains(game_dir)) { UISettings::values.game_dirs.append(game_dir); game_list->PopulateAsync(UISettings::values.game_dirs); @@ -3181,14 +3185,14 @@ void GMainWindow::OnMenuLoadFile() { "%1 is an identifier for the Switch executable file extensions.") .arg(extensions); const QString filename = QFileDialog::getOpenFileName( - this, tr("Load File"), UISettings::values.roms_path, file_filter); + this, tr("Load File"), QString::fromStdString(UISettings::values.roms_path), file_filter); is_load_file_select_active = false; if (filename.isEmpty()) { return; } - UISettings::values.roms_path = QFileInfo(filename).path(); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); BootGame(filename); } @@ -3221,7 +3225,8 @@ void GMainWindow::OnMenuInstallToNAND() { "Image (*.xci)"); QStringList filenames = QFileDialog::getOpenFileNames( - this, tr("Install Files"), UISettings::values.roms_path, file_filter); + this, tr("Install Files"), QString::fromStdString(UISettings::values.roms_path), + file_filter); if (filenames.isEmpty()) { return; @@ -3239,7 +3244,7 @@ void GMainWindow::OnMenuInstallToNAND() { } // Save folder location of the first selected file - UISettings::values.roms_path = QFileInfo(filenames[0]).path(); + UISettings::values.roms_path = QFileInfo(filenames[0]).path().toStdString(); int remaining = filenames.size(); @@ -3584,7 +3589,7 @@ void GMainWindow::OnExit() { void GMainWindow::OnSaveConfig() { system->ApplySettings(); - config->Save(); + config->SaveAllValues(); } void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { @@ -3840,7 +3845,7 @@ void GMainWindow::OnConfigure() { Settings::values.disabled_addons.clear(); - config = std::make_unique<Config>(); + config = std::make_unique<QtConfig>(); UISettings::values.reset_to_defaults = false; UISettings::values.game_dirs = std::move(old_game_dirs); @@ -3875,7 +3880,7 @@ void GMainWindow::OnConfigure() { UISettings::values.configuration_applied = false; - config->Save(); + config->SaveAllValues(); if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { render_window->installEventFilter(render_window); @@ -4091,7 +4096,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file UISettings::values.configuration_applied = false; if (!is_powered_on) { - config->Save(); + config->SaveAllValues(); } } @@ -4324,7 +4329,7 @@ void GMainWindow::OnAlbum() { system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer); const auto filename = QString::fromStdString(album_nca->GetFullPath()); - UISettings::values.roms_path = QFileInfo(filename).path(); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); BootGame(filename, AlbumId); } @@ -4348,7 +4353,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { system->GetAppletManager().SetCabinetMode(mode); const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); - UISettings::values.roms_path = QFileInfo(filename).path(); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); BootGame(filename, CabinetId); } @@ -4371,7 +4376,7 @@ void GMainWindow::OnMiiEdit() { system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); - UISettings::values.roms_path = QFileInfo(filename).path(); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); BootGame(filename, MiiEditId); } @@ -4396,7 +4401,7 @@ void GMainWindow::OnOpenControllerMenu() { system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller); const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); - UISettings::values.roms_path = QFileInfo(filename).path(); + UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); BootGame(filename, ControllerAppletId); } @@ -4590,7 +4595,8 @@ void GMainWindow::UpdateStatusBar() { void GMainWindow::UpdateGPUAccuracyButton() { const auto gpu_accuracy = Settings::values.gpu_accuracy.GetValue(); - const auto gpu_accuracy_text = Config::gpu_accuracy_texts_map.find(gpu_accuracy)->second; + const auto gpu_accuracy_text = + ConfigurationShared::gpu_accuracy_texts_map.find(gpu_accuracy)->second; gpu_accuracy_button->setText(gpu_accuracy_text.toUpper()); gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GpuAccuracy::Normal); } @@ -4599,31 +4605,32 @@ void GMainWindow::UpdateDockedButton() { const auto console_mode = Settings::values.use_docked_mode.GetValue(); dock_status_button->setChecked(Settings::IsDockedMode()); dock_status_button->setText( - Config::use_docked_mode_texts_map.find(console_mode)->second.toUpper()); + ConfigurationShared::use_docked_mode_texts_map.find(console_mode)->second.toUpper()); } void GMainWindow::UpdateAPIText() { const auto api = Settings::values.renderer_backend.GetValue(); - const auto renderer_status_text = Config::renderer_backend_texts_map.find(api)->second; + const auto renderer_status_text = + ConfigurationShared::renderer_backend_texts_map.find(api)->second; renderer_status_button->setText( api == Settings::RendererBackend::OpenGL - ? tr("%1 %2").arg( - renderer_status_text.toUpper(), - Config::shader_backend_texts_map.find(Settings::values.shader_backend.GetValue()) - ->second) + ? tr("%1 %2").arg(renderer_status_text.toUpper(), + ConfigurationShared::shader_backend_texts_map + .find(Settings::values.shader_backend.GetValue()) + ->second) : renderer_status_text.toUpper()); } void GMainWindow::UpdateFilterText() { const auto filter = Settings::values.scaling_filter.GetValue(); - const auto filter_text = Config::scaling_filter_texts_map.find(filter)->second; + const auto filter_text = ConfigurationShared::scaling_filter_texts_map.find(filter)->second; filter_status_button->setText(filter == Settings::ScalingFilter::Fsr ? tr("FSR") : filter_text.toUpper()); } void GMainWindow::UpdateAAText() { const auto aa_mode = Settings::values.anti_aliasing.GetValue(); - const auto aa_text = Config::anti_aliasing_texts_map.find(aa_mode)->second; + const auto aa_text = ConfigurationShared::anti_aliasing_texts_map.find(aa_mode)->second; aa_status_button->setText(aa_mode == Settings::AntiAliasing::None ? QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "NO AA")) : aa_text.toUpper()); @@ -4926,6 +4933,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UpdateUISettings(); game_list->SaveInterfaceLayout(); + UISettings::SaveWindowState(); hotkey_registry.SaveHotkeys(); // Unload controllers early @@ -5080,9 +5088,9 @@ static void AdjustLinkColor() { } void GMainWindow::UpdateUITheme() { - const QString default_theme = - QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second); - QString current_theme = UISettings::values.theme; + const QString default_theme = QString::fromUtf8( + UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second); + QString current_theme = QString::fromStdString(UISettings::values.theme); if (current_theme.isEmpty()) { current_theme = default_theme; @@ -5110,7 +5118,7 @@ void GMainWindow::UpdateUITheme() { QFile f(theme_uri); if (!f.open(QFile::ReadOnly | QFile::Text)) { LOG_ERROR(Frontend, "Unable to open style \"{}\", fallback to the default theme", - UISettings::values.theme.toStdString()); + UISettings::values.theme); current_theme = default_theme; } } @@ -5123,7 +5131,7 @@ void GMainWindow::UpdateUITheme() { setStyleSheet(ts.readAll()); } else { LOG_ERROR(Frontend, "Unable to set style \"{}\", stylesheet file not found", - UISettings::values.theme.toStdString()); + UISettings::values.theme); qApp->setStyleSheet({}); setStyleSheet({}); } @@ -5132,27 +5140,28 @@ void GMainWindow::UpdateUITheme() { void GMainWindow::LoadTranslation() { bool loaded; - if (UISettings::values.language.isEmpty()) { + if (UISettings::values.language.empty()) { // If the selected language is empty, use system locale loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/")); } else { // Otherwise load from the specified file - loaded = translator.load(UISettings::values.language, QStringLiteral(":/languages/")); + loaded = translator.load(QString::fromStdString(UISettings::values.language), + QStringLiteral(":/languages/")); } if (loaded) { qApp->installTranslator(&translator); } else { - UISettings::values.language = QStringLiteral("en"); + UISettings::values.language = std::string("en"); } } void GMainWindow::OnLanguageChanged(const QString& locale) { - if (UISettings::values.language != QStringLiteral("en")) { + if (UISettings::values.language != std::string("en")) { qApp->removeTranslator(&translator); } - UISettings::values.language = locale; + UISettings::values.language = locale.toStdString(); LoadTranslation(); ui->retranslateUi(this); multiplayer_state->retranslateUi(); @@ -5178,7 +5187,7 @@ void GMainWindow::changeEvent(QEvent* event) { // UpdateUITheme is a decent work around if (event->type() == QEvent::PaletteChange) { const QPalette test_palette(qApp->palette()); - const QString current_theme = UISettings::values.theme; + const QString current_theme = QString::fromStdString(UISettings::values.theme); // Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too static QColor last_window_color; const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); @@ -5272,7 +5281,8 @@ static void SetHighDPIAttributes() { } int main(int argc, char* argv[]) { - std::unique_ptr<Config> config = std::make_unique<Config>(); + std::unique_ptr<QtConfig> config = std::make_unique<QtConfig>(); + UISettings::RestoreWindowState(config); bool has_broken_vulkan = false; bool is_child = false; if (CheckEnvVars(&is_child)) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 49ee1e1d2..c989c079d 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -15,6 +15,7 @@ #include "common/announce_multiplayer_room.h" #include "common/common_types.h" +#include "configuration/qt_config.h" #include "input_common/drivers/tas_input.h" #include "yuzu/compatibility_list.h" #include "yuzu/hotkeys.h" @@ -26,7 +27,7 @@ #include <QtDBus/QtDBus> #endif -class Config; +class QtConfig; class ClickableLabel; class EmuThread; class GameList; @@ -185,7 +186,7 @@ class GMainWindow : public QMainWindow { public: void filterBarSetChecked(bool state); void UpdateUITheme(); - explicit GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan); + explicit GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan); ~GMainWindow() override; bool DropAction(QDropEvent* event); @@ -521,7 +522,7 @@ private: QSlider* volume_slider = nullptr; QTimer status_bar_update_timer; - std::unique_ptr<Config> config; + std::unique_ptr<QtConfig> config; // Whether emulation is currently running in yuzu. bool emulation_running = false; diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp index 1c833767b..7bb7e95af 100644 --- a/src/yuzu/uisettings.cpp +++ b/src/yuzu/uisettings.cpp @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: 2016 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <QSettings> +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "yuzu/uisettings.h" #ifndef CANNOT_EXPLICITLY_INSTANTIATE @@ -15,6 +18,8 @@ template class Setting<unsigned long long>; } // namespace Settings #endif +namespace FS = Common::FS; + namespace UISettings { const Themes themes{{ @@ -28,10 +33,8 @@ const Themes themes{{ bool IsDarkTheme() { const auto& theme = UISettings::values.theme; - return theme == QStringLiteral("qdarkstyle") || - theme == QStringLiteral("qdarkstyle_midnight_blue") || - theme == QStringLiteral("colorful_dark") || - theme == QStringLiteral("colorful_midnight_blue"); + return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") || + theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue"); } Values values = {}; @@ -52,4 +55,58 @@ u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) { return height * 16 / 9; } +void SaveWindowState() { + const auto window_state_config_loc = + FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "window_state.ini"); + + void(FS::CreateParentDir(window_state_config_loc)); + QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); + + config.setValue(QStringLiteral("geometry"), values.geometry); + config.setValue(QStringLiteral("state"), values.state); + config.setValue(QStringLiteral("geometryRenderWindow"), values.renderwindow_geometry); + config.setValue(QStringLiteral("gameListHeaderState"), values.gamelist_header_state); + config.setValue(QStringLiteral("microProfileDialogGeometry"), values.microprofile_geometry); + + config.sync(); +} + +void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig) { + const auto window_state_config_loc = + FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "window_state.ini"); + + // Migrate window state from old location + if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) { + const auto config_loc = + FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "qt-config.ini"); + QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat); + + config.beginGroup(QStringLiteral("UI")); + config.beginGroup(QStringLiteral("UILayout")); + values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); + values.state = config.value(QStringLiteral("state")).toByteArray(); + values.renderwindow_geometry = + config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); + values.gamelist_header_state = + config.value(QStringLiteral("gameListHeaderState")).toByteArray(); + values.microprofile_geometry = + config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); + config.endGroup(); + config.endGroup(); + return; + } + + void(FS::CreateParentDir(window_state_config_loc)); + const QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat); + + values.geometry = config.value(QStringLiteral("geometry")).toByteArray(); + values.state = config.value(QStringLiteral("state")).toByteArray(); + values.renderwindow_geometry = + config.value(QStringLiteral("geometryRenderWindow")).toByteArray(); + values.gamelist_header_state = + config.value(QStringLiteral("gameListHeaderState")).toByteArray(); + values.microprofile_geometry = + config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray(); +} + } // namespace UISettings diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 3485a6347..549a39e1b 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -14,6 +14,7 @@ #include "common/common_types.h" #include "common/settings.h" #include "common/settings_enums.h" +#include "configuration/qt_config.h" using Settings::Category; using Settings::ConfirmStop; @@ -37,15 +38,15 @@ namespace UISettings { bool IsDarkTheme(); struct ContextualShortcut { - QString keyseq; - QString controller_keyseq; + std::string keyseq; + std::string controller_keyseq; int context; bool repeat; }; struct Shortcut { - QString name; - QString group; + std::string name; + std::string group; ContextualShortcut shortcut; }; @@ -58,11 +59,19 @@ enum class Theme { MidnightBlueColorful, }; +static constexpr Theme default_theme{ +#ifdef _WIN32 + Theme::DarkColorful +#else + Theme::DefaultColorful +#endif +}; + using Themes = std::array<std::pair<const char*, const char*>, 6>; extern const Themes themes; struct GameDir { - QString path; + std::string path; bool deep_scan = false; bool expanded = false; bool operator==(const GameDir& rhs) const { @@ -144,15 +153,15 @@ struct Values { Category::Screenshots}; Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; - QString roms_path; - QString symbols_path; - QString game_dir_deprecated; + std::string roms_path; + std::string symbols_path; + std::string game_dir_deprecated; bool game_dir_deprecated_deepscan; - QVector<UISettings::GameDir> game_dirs; + QVector<GameDir> game_dirs; QStringList recent_files; - QString language; + std::string language; - QString theme; + std::string theme; // Shortcut name <Shortcut, context> std::vector<Shortcut> shortcuts; @@ -206,6 +215,54 @@ extern Values values; u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); +void SaveWindowState(); +void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig); + +// This shouldn't have anything except static initializers (no functions). So +// QKeySequence(...).toString() is NOT ALLOWED HERE. +// 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. +// clang-format off +const std::array<Shortcut, 23> default_hotkeys{{ + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+M"), std::string("Home+Dpad_Right"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("-"), std::string("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("="), std::string("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+P"), std::string("Screenshot"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F8"), std::string("Home+L"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F10"), std::string("Home+X"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F9"), std::string("Home+R"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F4"), std::string("Home+Plus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+Q"), std::string("Home+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F11"), std::string("Home+B"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+O"), std::string(""), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F2"), std::string("Home+A"), Qt::WidgetWithChildrenShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F6"), std::string("R+Plus+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("F5"), std::string("L+Plus+Minus"), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F7"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F6"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F5"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F"), std::string(""), Qt::WindowShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+U"), std::string("Home+Y"), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+F9"), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}}, + {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Ctrl+S"), std::string(""), Qt::WindowShortcut, false}}, +}}; +// clang-format on + } // namespace UISettings Q_DECLARE_METATYPE(UISettings::GameDir*); + +// These metatype declarations cannot be in common/settings.h because core is devoid of QT +Q_DECLARE_METATYPE(Settings::CpuAccuracy); +Q_DECLARE_METATYPE(Settings::GpuAccuracy); +Q_DECLARE_METATYPE(Settings::FullscreenMode); +Q_DECLARE_METATYPE(Settings::NvdecEmulation); +Q_DECLARE_METATYPE(Settings::ResolutionSetup); +Q_DECLARE_METATYPE(Settings::ScalingFilter); +Q_DECLARE_METATYPE(Settings::AntiAliasing); +Q_DECLARE_METATYPE(Settings::RendererBackend); +Q_DECLARE_METATYPE(Settings::ShaderBackend); +Q_DECLARE_METATYPE(Settings::AstcRecompression); +Q_DECLARE_METATYPE(Settings::AstcDecodeMode); diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 46eddf423..fbeba8813 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -13,9 +13,6 @@ function(create_resource file output filename) endfunction() add_executable(yuzu-cmd - config.cpp - config.h - default_ini.h emu_window/emu_window_sdl2.cpp emu_window/emu_window_sdl2.h emu_window/emu_window_sdl2_gl.cpp @@ -25,14 +22,16 @@ add_executable(yuzu-cmd emu_window/emu_window_sdl2_vk.cpp emu_window/emu_window_sdl2_vk.h precompiled_headers.h + sdl_config.cpp + sdl_config.h yuzu.cpp yuzu.rc ) create_target_directory_groups(yuzu-cmd) -target_link_libraries(yuzu-cmd PRIVATE common core input_common) -target_link_libraries(yuzu-cmd PRIVATE inih::INIReader glad) +target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common) +target_link_libraries(yuzu-cmd PRIVATE glad) if (MSVC) target_link_libraries(yuzu-cmd PRIVATE getopt) endif() diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp deleted file mode 100644 index 0d25ff400..000000000 --- a/src/yuzu_cmd/config.cpp +++ /dev/null @@ -1,279 +0,0 @@ -// SPDX-FileCopyrightText: 2014 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <memory> -#include <optional> -#include <sstream> -#include <INIReader.h> -#include <SDL.h> -#include "common/fs/file.h" -#include "common/fs/fs.h" -#include "common/fs/path_util.h" -#include "common/logging/log.h" -#include "common/settings.h" -#include "core/hle/service/acc/profile_manager.h" -#include "input_common/main.h" -#include "yuzu_cmd/config.h" -#include "yuzu_cmd/default_ini.h" - -namespace FS = Common::FS; - -const std::filesystem::path default_config_path = - FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini"; - -Config::Config(std::optional<std::filesystem::path> config_path) - : sdl2_config_loc{config_path.value_or(default_config_path)}, - sdl2_config{std::make_unique<INIReader>(FS::PathToUTF8String(sdl2_config_loc))} { - Reload(); -} - -Config::~Config() = default; - -bool Config::LoadINI(const std::string& default_contents, bool retry) { - const auto config_loc_str = FS::PathToUTF8String(sdl2_config_loc); - if (sdl2_config->ParseError() < 0) { - if (retry) { - LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", - config_loc_str); - - void(FS::CreateParentDir(sdl2_config_loc)); - void(FS::WriteStringToFile(sdl2_config_loc, FS::FileType::TextFile, default_contents)); - - sdl2_config = std::make_unique<INIReader>(config_loc_str); - - return LoadINI(default_contents, false); - } - LOG_ERROR(Config, "Failed."); - return false; - } - LOG_INFO(Config, "Successfully loaded {}", config_loc_str); - return true; -} - -static const std::array<int, Settings::NativeButton::NumButtons> default_buttons = { - SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, - SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, - SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B, -}; - -static const std::array<int, Settings::NativeMotion::NumMotions> default_motions = { - SDL_SCANCODE_7, - SDL_SCANCODE_8, -}; - -static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs{{ - { - SDL_SCANCODE_UP, - SDL_SCANCODE_DOWN, - SDL_SCANCODE_LEFT, - SDL_SCANCODE_RIGHT, - SDL_SCANCODE_D, - }, - { - SDL_SCANCODE_I, - SDL_SCANCODE_K, - SDL_SCANCODE_J, - SDL_SCANCODE_L, - SDL_SCANCODE_D, - }, -}}; - -template <> -void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) { - std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); - if (setting_value.empty()) { - setting_value = setting.GetDefault(); - } - setting = std::move(setting_value); -} - -template <> -void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) { - setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); -} - -template <typename Type, bool ranged> -void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) { - setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(), - static_cast<long>(setting.GetDefault()))); -} - -void Config::ReadCategory(Settings::Category category) { - for (const auto setting : Settings::values.linkage.by_category[category]) { - const char* category_name = [&]() { - if (category == Settings::Category::Controls) { - // For compatibility with older configs - return "ControlsGeneral"; - } else { - return Settings::TranslateCategory(category); - } - }(); - std::string setting_value = - sdl2_config->Get(category_name, setting->GetLabel(), setting->DefaultToString()); - setting->LoadString(setting_value); - } -} - -void Config::ReadValues() { - // Controls - ReadCategory(Settings::Category::Controls); - - for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { - auto& player = Settings::values.players.GetValue()[p]; - - const auto group = fmt::format("ControlsP{}", p); - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - player.buttons[i] = - sdl2_config->Get(group, Settings::NativeButton::mapping[i], default_param); - if (player.buttons[i].empty()) { - player.buttons[i] = default_param; - } - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_analogs[i][4], 0.5f); - player.analogs[i] = - sdl2_config->Get(group, Settings::NativeAnalog::mapping[i], default_param); - if (player.analogs[i].empty()) { - player.analogs[i] = default_param; - } - } - - for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { - const std::string default_param = - InputCommon::GenerateKeyboardParam(default_motions[i]); - auto& player_motions = player.motions[i]; - - player_motions = - sdl2_config->Get(group, Settings::NativeMotion::mapping[i], default_param); - if (player_motions.empty()) { - player_motions = default_param; - } - } - - player.connected = sdl2_config->GetBoolean(group, "connected", false); - } - - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); - Settings::values.debug_pad_buttons[i] = sdl2_config->Get( - "ControlsGeneral", std::string("debug_pad_") + Settings::NativeButton::mapping[i], - default_param); - if (Settings::values.debug_pad_buttons[i].empty()) - Settings::values.debug_pad_buttons[i] = default_param; - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - std::string default_param = InputCommon::GenerateAnalogParamFromKeys( - default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], - default_analogs[i][3], default_analogs[i][4], 0.5f); - Settings::values.debug_pad_analogs[i] = sdl2_config->Get( - "ControlsGeneral", std::string("debug_pad_") + Settings::NativeAnalog::mapping[i], - default_param); - if (Settings::values.debug_pad_analogs[i].empty()) - Settings::values.debug_pad_analogs[i] = default_param; - } - - Settings::values.touchscreen.enabled = - sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true); - Settings::values.touchscreen.rotation_angle = - sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0); - Settings::values.touchscreen.diameter_x = - sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); - Settings::values.touchscreen.diameter_y = - sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); - - int num_touch_from_button_maps = - sdl2_config->GetInteger("ControlsGeneral", "touch_from_button_map", 0); - if (num_touch_from_button_maps > 0) { - for (int i = 0; i < num_touch_from_button_maps; ++i) { - Settings::TouchFromButtonMap map; - map.name = sdl2_config->Get("ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + - std::string("_name"), - "default"); - const int num_touch_maps = sdl2_config->GetInteger( - "ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"), - 0); - map.buttons.reserve(num_touch_maps); - - for (int j = 0; j < num_touch_maps; ++j) { - std::string touch_mapping = - sdl2_config->Get("ControlsGeneral", - std::string("touch_from_button_maps_") + std::to_string(i) + - std::string("_bind_") + std::to_string(j), - ""); - map.buttons.emplace_back(std::move(touch_mapping)); - } - - Settings::values.touch_from_button_maps.emplace_back(std::move(map)); - } - } else { - Settings::values.touch_from_button_maps.emplace_back( - Settings::TouchFromButtonMap{"default", {}}); - num_touch_from_button_maps = 1; - } - Settings::values.touch_from_button_map_index = std::clamp( - Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); - - ReadCategory(Settings::Category::Audio); - ReadCategory(Settings::Category::Core); - ReadCategory(Settings::Category::Cpu); - ReadCategory(Settings::Category::CpuDebug); - ReadCategory(Settings::Category::CpuUnsafe); - ReadCategory(Settings::Category::Renderer); - ReadCategory(Settings::Category::RendererAdvanced); - ReadCategory(Settings::Category::RendererDebug); - ReadCategory(Settings::Category::System); - ReadCategory(Settings::Category::SystemAudio); - ReadCategory(Settings::Category::DataStorage); - ReadCategory(Settings::Category::Debugging); - ReadCategory(Settings::Category::DebuggingGraphics); - ReadCategory(Settings::Category::Miscellaneous); - ReadCategory(Settings::Category::Network); - ReadCategory(Settings::Category::WebService); - - // Data Storage - FS::SetYuzuPath(FS::YuzuPath::NANDDir, - sdl2_config->Get("Data Storage", "nand_directory", - FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); - FS::SetYuzuPath(FS::YuzuPath::SDMCDir, - sdl2_config->Get("Data Storage", "sdmc_directory", - FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); - FS::SetYuzuPath(FS::YuzuPath::LoadDir, - sdl2_config->Get("Data Storage", "load_directory", - FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); - FS::SetYuzuPath(FS::YuzuPath::DumpDir, - sdl2_config->Get("Data Storage", "dump_directory", - FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); - - // Debugging - Settings::values.record_frame_times = - sdl2_config->GetBoolean("Debugging", "record_frame_times", false); - - const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); - std::stringstream ss(title_list); - std::string line; - while (std::getline(ss, line, '|')) { - const auto title_id = std::strtoul(line.c_str(), nullptr, 16); - const auto disabled_list = sdl2_config->Get("AddOns", "disabled_" + line, ""); - - std::stringstream inner_ss(disabled_list); - std::string inner_line; - std::vector<std::string> out; - while (std::getline(inner_ss, inner_line, '|')) { - out.push_back(inner_line); - } - - Settings::values.disabled_addons.insert_or_assign(title_id, out); - } -} - -void Config::Reload() { - LoadINI(DefaultINI::sdl2_config_file); - ReadValues(); -} diff --git a/src/yuzu_cmd/config.h b/src/yuzu_cmd/config.h deleted file mode 100644 index 512591a39..000000000 --- a/src/yuzu_cmd/config.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-FileCopyrightText: 2014 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include <filesystem> -#include <memory> -#include <optional> -#include <string> - -#include "common/settings.h" - -class INIReader; - -class Config { - std::filesystem::path sdl2_config_loc; - std::unique_ptr<INIReader> sdl2_config; - - bool LoadINI(const std::string& default_contents = "", bool retry = true); - void ReadValues(); - -public: - explicit Config(std::optional<std::filesystem::path> config_path); - ~Config(); - - void Reload(); - -private: - /** - * Applies a value read from the sdl2_config to a Setting. - * - * @param group The name of the INI group - * @param setting The yuzu setting to modify - */ - template <typename Type, bool ranged> - void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting); - void ReadCategory(Settings::Category category); -}; diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h deleted file mode 100644 index 119e22183..000000000 --- a/src/yuzu_cmd/default_ini.h +++ /dev/null @@ -1,553 +0,0 @@ -// SPDX-FileCopyrightText: 2014 Citra Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -namespace DefaultINI { - -const char* sdl2_config_file = - R"( -[ControlsP0] -# The input devices and parameters for each Switch native input -# The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ... -# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." -# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values - -# Indicates if this player should be connected at boot -# 0 (default): Disabled, 1: Enabled -connected= - -# for button input, the following devices are available: -# - "keyboard" (default) for keyboard input. Required parameters: -# - "code": the code of the key to bind -# - "sdl" for joystick input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "button"(optional): the index of the button to bind -# - "hat"(optional): the index of the hat to bind as direction buttons -# - "axis"(optional): the index of the axis to bind -# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" -# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is -# triggered if the axis value crosses -# - "direction"(only used for axis): "+" means the button is triggered when the axis value -# is greater than the threshold; "-" means the button is triggered when the axis value -# is smaller than the threshold -button_a= -button_b= -button_x= -button_y= -button_lstick= -button_rstick= -button_l= -button_r= -button_zl= -button_zr= -button_plus= -button_minus= -button_dleft= -button_dup= -button_dright= -button_ddown= -button_lstick_left= -button_lstick_up= -button_lstick_right= -button_lstick_down= -button_sl= -button_sr= -button_home= -button_screenshot= - -# for analog input, the following devices are available: -# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: -# - "up", "down", "left", "right": sub-devices for each direction. -# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" -# - "modifier": sub-devices as a modifier. -# - "modifier_scale": a float number representing the applied modifier scale to the analog input. -# Must be in range of 0.0-1.0. Defaults to 0.5 -# - "sdl" for joystick input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "axis_x": the index of the axis to bind as x-axis (default to 0) -# - "axis_y": the index of the axis to bind as y-axis (default to 1) -lstick= -rstick= - -# for motion input, the following devices are available: -# - "keyboard" (default) for emulating random motion input from buttons. Required parameters: -# - "code": the code of the key to bind -# - "sdl" for motion input using SDL. Required parameters: -# - "guid": SDL identification GUID of the joystick -# - "port": the index of the joystick to bind -# - "motion": the index of the motion sensor to bind -# - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters: -# - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001" -# - "port": the port of the cemu hook server -# - "pad": the index of the joystick -# - "motion": the index of the motion sensor of the joystick to bind -motionleft= -motionright= - -[ControlsGeneral] -# To use the debug_pad, prepend `debug_pad_` before each button setting above. -# i.e. debug_pad_button_a= - -# Enable debug pad inputs to the guest -# 0 (default): Disabled, 1: Enabled -debug_pad_enabled = - -# Enable sdl raw input. Allows to configure up to 8 xinput controllers. -# 0 (default): Disabled, 1: Enabled -enable_raw_input = - -# Enable yuzu joycon driver instead of SDL drive. -# 0: Disabled, 1 (default): Enabled -enable_joycon_driver = - -# Emulates an analog input from buttons. Allowing to dial any angle. -# 0 (default): Disabled, 1: Enabled -emulate_analog_keyboard = - -# Whether to enable or disable vibration -# 0: Disabled, 1 (default): Enabled -vibration_enabled= - -# Whether to enable or disable accurate vibrations -# 0 (default): Disabled, 1: Enabled -enable_accurate_vibrations= - -# Enables controller motion inputs -# 0: Disabled, 1 (default): Enabled -motion_enabled = - -# Defines the udp device's touch screen coordinate system for cemuhookudp devices -# - "min_x", "min_y", "max_x", "max_y" -touch_device= - -# for mapping buttons to touch inputs. -#touch_from_button_map=1 -#touch_from_button_maps_0_name=default -#touch_from_button_maps_0_count=2 -#touch_from_button_maps_0_bind_0=foo -#touch_from_button_maps_0_bind_1=bar -# etc. - -# List of Cemuhook UDP servers, delimited by ','. -# Default: 127.0.0.1:26760 -# Example: 127.0.0.1:26760,123.4.5.67:26761 -udp_input_servers = - -# Enable controlling an axis via a mouse input. -# 0 (default): Off, 1: On -mouse_panning = - -# Set mouse panning horizontal sensitivity. -# Default: 50.0 -mouse_panning_x_sensitivity = - -# Set mouse panning vertical sensitivity. -# Default: 50.0 -mouse_panning_y_sensitivity = - -# Set mouse panning deadzone horizontal counterweight. -# Default: 0.0 -mouse_panning_deadzone_x_counterweight = - -# Set mouse panning deadzone vertical counterweight. -# Default: 0.0 -mouse_panning_deadzone_y_counterweight = - -# Set mouse panning stick decay strength. -# Default: 22.0 -mouse_panning_decay_strength = - -# Set mouse panning stick minimum decay. -# Default: 5.0 -mouse_panning_minimum_decay = - -# Emulate an analog control stick from keyboard inputs. -# 0 (default): Disabled, 1: Enabled -emulate_analog_keyboard = - -# Enable mouse inputs to the guest -# 0 (default): Disabled, 1: Enabled -mouse_enabled = - -# Enable keyboard inputs to the guest -# 0 (default): Disabled, 1: Enabled -keyboard_enabled = - -)" - R"( -[Core] -# Whether to use multi-core for CPU emulation -# 0: Disabled, 1 (default): Enabled -use_multi_core = - -# Enable unsafe extended guest system memory layout (8GB DRAM) -# 0 (default): Disabled, 1: Enabled -use_unsafe_extended_memory_layout = - -[Cpu] -# Adjusts various optimizations. -# Auto-select mode enables choice unsafe optimizations. -# Accurate enables only safe optimizations. -# Unsafe allows any unsafe optimizations. -# 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations -cpu_accuracy = - -# Allow disabling safe optimizations. -# 0 (default): Disabled, 1: Enabled -cpu_debug_mode = - -# Enable inline page tables optimization (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_page_tables = - -# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) -# 0: Disabled, 1 (default): Enabled -cpuopt_block_linking = - -# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) -# 0: Disabled, 1 (default): Enabled -cpuopt_return_stack_buffer = - -# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) -# 0: Disabled, 1 (default): Enabled -cpuopt_fast_dispatcher = - -# Enable context elimination CPU Optimization (reduce host memory use for guest context) -# 0: Disabled, 1 (default): Enabled -cpuopt_context_elimination = - -# Enable constant propagation CPU optimization (basic IR optimization) -# 0: Disabled, 1 (default): Enabled -cpuopt_const_prop = - -# Enable miscellaneous CPU optimizations (basic IR optimization) -# 0: Disabled, 1 (default): Enabled -cpuopt_misc_ir = - -# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) -# 0: Disabled, 1 (default): Enabled -cpuopt_reduce_misalign_checks = - -# Enable Host MMU Emulation (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_fastmem = - -# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_fastmem_exclusives = - -# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_recompile_exclusives = - -# Enable optimization to ignore invalid memory accesses (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_ignore_memory_aborts = - -# Enable unfuse FMA (improve performance on CPUs without FMA) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_unfuse_fma = - -# Enable faster FRSQRTE and FRECPE -# Only enabled if cpu_accuracy is set to Unsafe. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_reduce_fp_error = - -# Enable faster ASIMD instructions (32 bits only) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_ignore_standard_fpcr = - -# Enable inaccurate NaN handling -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_inaccurate_nan = - -# Disable address space checks (64 bits only) -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_fastmem_check = - -# Enable faster exclusive instructions -# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. -# 0: Disabled, 1 (default): Enabled -cpuopt_unsafe_ignore_global_monitor = - -)" - R"( -[Renderer] -# Which backend API to use. -# 0: OpenGL, 1 (default): Vulkan -backend = - -# Whether to enable asynchronous presentation (Vulkan only) -# 0 (default): Off, 1: On -async_presentation = - -# Enable graphics API debugging mode. -# 0 (default): Disabled, 1: Enabled -debug = - -# Enable shader feedback. -# 0 (default): Disabled, 1: Enabled -renderer_shader_feedback = - -# Enable Nsight Aftermath crash dumps -# 0 (default): Disabled, 1: Enabled -nsight_aftermath = - -# Disable shader loop safety checks, executing the shader without loop logic changes -# 0 (default): Disabled, 1: Enabled -disable_shader_loop_safety_checks = - -# Which Vulkan physical device to use (defaults to 0) -vulkan_device = - -# 0: 0.5x (360p/540p) [EXPERIMENTAL] -# 1: 0.75x (540p/810p) [EXPERIMENTAL] -# 2 (default): 1x (720p/1080p) -# 3: 1.5x (1080p/1620p) [EXPERIMENTAL] -# 4: 2x (1440p/2160p) -# 5: 3x (2160p/3240p) -# 6: 4x (2880p/4320p) -# 7: 5x (3600p/5400p) -# 8: 6x (4320p/6480p) -# 9: 7x (5040p/7560p) -# 10: 8x (5760/8640p) -resolution_setup = - -# Pixel filter to use when up- or down-sampling rendered frames. -# 0: Nearest Neighbor -# 1 (default): Bilinear -# 2: Bicubic -# 3: Gaussian -# 4: ScaleForce -# 5: AMD FidelityFX™️ Super Resolution -scaling_filter = - -# Anti-Aliasing (AA) -# 0 (default): None, 1: FXAA, 2: SMAA -anti_aliasing = - -# Whether to use fullscreen or borderless window mode -# 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen -fullscreen_mode = - -# Aspect ratio -# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window -aspect_ratio = - -# Anisotropic filtering -# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x -max_anisotropy = - -# Whether to enable VSync or not. -# OpenGL: Values other than 0 enable VSync -# Vulkan: FIFO is selected if the requested mode is not supported by the driver. -# FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. -# FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. -# Mailbox can have lower latency than FIFO and does not tear but may drop frames. -# Immediate (no synchronization) just presents whatever is available and can exhibit tearing. -# 0: Immediate (Off), 1: Mailbox, 2 (Default): FIFO (On), 3: FIFO Relaxed -use_vsync = - -# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is -# not available and GLASM is selected, GLSL will be used. -# 0: GLSL, 1 (default): GLASM, 2: SPIR-V -shader_backend = - -# Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory. -# 0: Off, 1 (default): On -use_reactive_flushing = - -# Whether to allow asynchronous shader building. -# 0 (default): Off, 1: On -use_asynchronous_shaders = - -# NVDEC emulation. -# 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding -nvdec_emulation = - -# Accelerate ASTC texture decoding. -# 0: Off, 1 (default): On -accelerate_astc = - -# Decode ASTC textures asynchronously. -# 0 (default): Off, 1: On -async_astc = - -# Recompress ASTC textures to a different format. -# 0 (default): Uncompressed, 1: BC1 (Low quality), 2: BC3: (Medium quality) -async_astc = - -# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value -# 0: Off, 1: On (default) -use_speed_limit = - -# Limits the speed of the game to run no faster than this value as a percentage of target speed -# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) -speed_limit = - -# Whether to use disk based shader cache -# 0: Off, 1 (default): On -use_disk_shader_cache = - -# Which gpu accuracy level to use -# 0: Normal, 1 (default): High, 2: Extreme (Very slow) -gpu_accuracy = - -# Whether to use asynchronous GPU emulation -# 0 : Off (slow), 1 (default): On (fast) -use_asynchronous_gpu_emulation = - -# Inform the guest that GPU operations completed more quickly than they did. -# 0: Off, 1 (default): On -use_fast_gpu_time = - -# Whether to use garbage collection or not for GPU caches. -# 0 (default): Off, 1: On -use_caches_gc = - -# The clear color for the renderer. What shows up on the sides of the bottom screen. -# Must be in range of 0-255. Defaults to 0 for all. -bg_red = -bg_blue = -bg_green = - -)" - R"( -[Audio] -# Which audio output engine to use. -# auto (default): Auto-select -# cubeb: Cubeb audio engine (if available) -# sdl2: SDL2 audio engine (if available) -# null: No audio output -output_engine = - -# Which audio device to use. -# auto (default): Auto-select -output_device = - -# Output volume. -# 100 (default): 100%, 0; mute -volume = - -[Data Storage] -# Whether to create a virtual SD card. -# 1 (default): Yes, 0: No -use_virtual_sd = - -# Whether or not to enable gamecard emulation -# 1: Yes, 0 (default): No -gamecard_inserted = - -# Whether or not the gamecard should be emulated as the current game -# If 'gamecard_inserted' is 0 this setting is irrelevant -# 1: Yes, 0 (default): No -gamecard_current_game = - -# Path to an XCI file to use as the gamecard -# If 'gamecard_inserted' is 0 this setting is irrelevant -# If 'gamecard_current_game' is 1 this setting is irrelevant -gamecard_path = - -[System] -# Whether the system is docked -# 1 (default): Yes, 0: No -use_docked_mode = - -# Sets the seed for the RNG generator built into the switch -# rng_seed will be ignored and randomly generated if rng_seed_enabled is false -rng_seed_enabled = -rng_seed = - -# Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service -# This will auto-increment, with the time set being the time the game is started -# This override will only occur if custom_rtc_enabled is true, otherwise the current time is used -custom_rtc_enabled = -custom_rtc = - -# Sets the systems language index -# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, -# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, -# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese -language_index = - -# The system region that yuzu will use during emulation -# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan -region_index = - -# The system time zone that yuzu will use during emulation -# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone -time_zone_index = - -# Sets the sound output mode. -# 0: Mono, 1 (default): Stereo, 2: Surround -sound_index = - -[Miscellaneous] -# A filter which removes logs below a certain logging level. -# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical -log_filter = *:Trace - -# Use developer keys -# 0 (default): Disabled, 1: Enabled -use_dev_keys = - -[Debugging] -# Record frame time data, can be found in the log directory. Boolean value -record_frame_times = -# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them -dump_exefs=false -# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them -dump_nso=false -# Determines whether or not yuzu will save the filesystem access log. -enable_fs_access_log=false -# Enables verbose reporting services -reporting_services = -# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode -# false: Retail/Normal Mode (default), true: Kiosk Mode -quest_flag = -# Determines whether debug asserts should be enabled, which will throw an exception on asserts. -# false: Disabled (default), true: Enabled -use_debug_asserts = -# Determines whether unimplemented HLE service calls should be automatically stubbed. -# false: Disabled (default), true: Enabled -use_auto_stub = -# Enables/Disables the macro JIT compiler -disable_macro_jit=false -# Determines whether to enable the GDB stub and wait for the debugger to attach before running. -# false: Disabled (default), true: Enabled -use_gdbstub=false -# The port to use for the GDB server, if it is enabled. -gdbstub_port=6543 - -[WebService] -# Whether or not to enable telemetry -# 0: No, 1 (default): Yes -enable_telemetry = -# URL for Web API -web_api_url = https://api.yuzu-emu.org -# Username and token for yuzu Web Service -# See https://profile.yuzu-emu.org/ for more info -yuzu_username = -yuzu_token = - -[Network] -# Name of the network interface device to use with yuzu LAN play. -# e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo' -# e.g. On Windows: 'Ethernet', 'Wi-Fi' -network_interface = - -[AddOns] -# Used to disable add-ons -# List of title IDs of games that will have add-ons disabled (separated by '|'): -title_ids = -# For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|') -# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey -)"; -} // namespace DefaultINI diff --git a/src/yuzu_cmd/sdl_config.cpp b/src/yuzu_cmd/sdl_config.cpp new file mode 100644 index 000000000..39fd8050c --- /dev/null +++ b/src/yuzu_cmd/sdl_config.cpp @@ -0,0 +1,257 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// SDL will break our main function in yuzu-cmd if we don't define this before adding SDL.h +#define SDL_MAIN_HANDLED +#include <SDL.h> + +#include "input_common/main.h" +#include "sdl_config.h" + +const std::array<int, Settings::NativeButton::NumButtons> SdlConfig::default_buttons = { + SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T, + SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W, + SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B, +}; + +const std::array<int, Settings::NativeMotion::NumMotions> SdlConfig::default_motions = { + SDL_SCANCODE_7, + SDL_SCANCODE_8, +}; + +const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> SdlConfig::default_analogs{ + { + { + SDL_SCANCODE_UP, + SDL_SCANCODE_DOWN, + SDL_SCANCODE_LEFT, + SDL_SCANCODE_RIGHT, + }, + { + SDL_SCANCODE_I, + SDL_SCANCODE_K, + SDL_SCANCODE_J, + SDL_SCANCODE_L, + }, + }}; + +const std::array<int, 2> SdlConfig::default_stick_mod = { + SDL_SCANCODE_D, + 0, +}; + +const std::array<int, 2> SdlConfig::default_ringcon_analogs{{ + 0, + 0, +}}; + +SdlConfig::SdlConfig(const std::optional<std::string> config_path) { + Initialize(config_path); + ReadSdlValues(); + SaveSdlValues(); +} + +SdlConfig::~SdlConfig() { + if (global) { + SdlConfig::SaveAllValues(); + } +} + +void SdlConfig::ReloadAllValues() { + Reload(); + ReadSdlValues(); + SaveSdlValues(); +} + +void SdlConfig::SaveAllValues() { + Save(); + SaveSdlValues(); +} + +void SdlConfig::ReadSdlValues() { + ReadSdlControlValues(); +} + +void SdlConfig::ReadSdlControlValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { + ReadSdlPlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + ReadDebugControlValues(); + ReadHidbusValues(); + + EndGroup(); +} + +void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix.append("player_").append(ToString(player_index)).append("_"); + } + + auto& player = Settings::values.players.GetValue()[player_index]; + if (IsCustomConfig()) { + const auto profile_name = + ReadStringSetting(std::string(player_prefix).append("profile_name")); + if (profile_name.empty()) { + // Use the global input config + player = Settings::values.players.GetValue(true)[player_index]; + return; + } + } + + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + auto& player_buttons = player.buttons[i]; + + player_buttons = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param); + if (player_buttons.empty()) { + player_buttons = default_param; + } + } + + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + auto& player_analogs = player.analogs[i]; + + player_analogs = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param); + if (player_analogs.empty()) { + player_analogs = default_param; + } + } + + for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); + auto& player_motions = player.motions[i]; + + player_motions = ReadStringSetting( + std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param); + if (player_motions.empty()) { + player_motions = default_param; + } + } +} + +void SdlConfig::ReadDebugControlValues() { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i]; + debug_pad_buttons = ReadStringSetting( + std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param); + if (debug_pad_buttons.empty()) { + debug_pad_buttons = default_param; + } + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i]; + debug_pad_analogs = ReadStringSetting( + std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param); + if (debug_pad_analogs.empty()) { + debug_pad_analogs = default_param; + } + } +} + +void SdlConfig::ReadHidbusValues() { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + auto& ringcon_analogs = Settings::values.ringcon_analogs; + + ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param); + if (ringcon_analogs.empty()) { + ringcon_analogs = default_param; + } +} + +void SdlConfig::SaveSdlValues() { + SaveSdlControlValues(); + + WriteToIni(); +} + +void SdlConfig::SaveSdlControlValues() { + BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); + + Settings::values.players.SetGlobal(!IsCustomConfig()); + for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { + SaveSdlPlayerValues(p); + } + if (IsCustomConfig()) { + EndGroup(); + return; + } + SaveDebugControlValues(); + SaveHidbusValues(); + + EndGroup(); +} + +void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) { + std::string player_prefix; + if (type != ConfigType::InputProfile) { + player_prefix = std::string("player_").append(ToString(player_index)).append("_"); + } + + const auto& player = Settings::values.players.GetValue()[player_index]; + if (IsCustomConfig() && player.profile_name.empty()) { + // No custom profile selected + return; + } + + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]), + player.buttons[i], std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), + player.analogs[i], std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]); + WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), + player.motions[i], std::make_optional(default_param)); + } +} + +void SdlConfig::SaveDebugControlValues() { + for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { + const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]); + WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), + Settings::values.debug_pad_buttons[i], std::make_optional(default_param)); + } + for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + default_analogs[i][0], default_analogs[i][1], default_analogs[i][2], + default_analogs[i][3], default_stick_mod[i], 0.5f); + WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), + Settings::values.debug_pad_analogs[i], std::make_optional(default_param)); + } +} + +void SdlConfig::SaveHidbusValues() { + const std::string default_param = InputCommon::GenerateAnalogParamFromKeys( + 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f); + WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs, + std::make_optional(default_param)); +} + +std::vector<Settings::BasicSetting*>& SdlConfig::FindRelevantList(Settings::Category category) { + return Settings::values.linkage.by_category[category]; +} diff --git a/src/yuzu_cmd/sdl_config.h b/src/yuzu_cmd/sdl_config.h new file mode 100644 index 000000000..1fd1c692d --- /dev/null +++ b/src/yuzu_cmd/sdl_config.h @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "frontend_common/config.h" + +class SdlConfig final : public Config { +public: + explicit SdlConfig(std::optional<std::string> config_path); + ~SdlConfig() override; + + void ReloadAllValues() override; + void SaveAllValues() override; + +protected: + void ReadSdlValues(); + void ReadSdlPlayerValues(std::size_t player_index); + void ReadSdlControlValues(); + void ReadHidbusValues() override; + void ReadDebugControlValues() override; + void ReadPathValues() override {} + void ReadShortcutValues() override {} + void ReadUIValues() override {} + void ReadUIGamelistValues() override {} + void ReadUILayoutValues() override {} + void ReadMultiplayerValues() override {} + + void SaveSdlValues(); + void SaveSdlPlayerValues(std::size_t player_index); + void SaveSdlControlValues(); + void SaveHidbusValues() override; + void SaveDebugControlValues() override; + void SavePathValues() override {} + void SaveShortcutValues() override {} + void SaveUIValues() override {} + void SaveUIGamelistValues() override {} + void SaveUILayoutValues() override {} + void SaveMultiplayerValues() override {} + + std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override; + +public: + static const std::array<int, Settings::NativeButton::NumButtons> default_buttons; + static const std::array<int, Settings::NativeMotion::NumMotions> default_motions; + static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs; + static const std::array<int, 2> default_stick_mod; + static const std::array<int, 2> default_ringcon_analogs; +}; diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 087cfaa26..0416d5951 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -29,10 +29,11 @@ #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" #include "core/telemetry_session.h" +#include "frontend_common/config.h" #include "input_common/main.h" #include "network/network.h" +#include "sdl_config.h" #include "video_core/renderer_base.h" -#include "yuzu_cmd/config.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h" #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" #include "yuzu_cmd/emu_window/emu_window_sdl2_null.h" @@ -300,7 +301,7 @@ int main(int argc, char** argv) { } } - Config config{config_path}; + SdlConfig config{config_path}; // apply the log_filter setting // the logger was initialized before and doesn't pick up the filter on its own |