summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules6
-rw-r--r--CMakeLists.txt1
-rw-r--r--CMakeModules/Findinih.cmake27
-rw-r--r--dist/languages/.tx/config5
-rw-r--r--externals/CMakeLists.txt8
-rw-r--r--externals/inih/CMakeLists.txt13
m---------externals/inih/inih0
m---------externals/simpleini0
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/android/app/build.gradle.kts1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt42
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt24
-rw-r--r--src/android/app/src/main/jni/CMakeLists.txt11
-rw-r--r--src/android/app/src/main/jni/android_config.cpp70
-rw-r--r--src/android/app/src/main/jni/android_config.h41
-rw-r--r--src/android/app/src/main/jni/android_settings.cpp (renamed from src/android/app/src/main/jni/uisettings.cpp)2
-rw-r--r--src/android/app/src/main/jni/android_settings.h (renamed from src/android/app/src/main/jni/uisettings.h)0
-rw-r--r--src/android/app/src/main/jni/config.cpp330
-rw-r--r--src/android/app/src/main/jni/config.h47
-rw-r--r--src/android/app/src/main/jni/default_ini.h511
-rw-r--r--src/android/app/src/main/jni/native.cpp15
-rw-r--r--src/android/app/src/main/jni/native_config.cpp23
-rw-r--r--src/common/settings.cpp4
-rw-r--r--src/common/settings.h42
-rw-r--r--src/core/CMakeLists.txt9
-rw-r--r--src/core/hid/emulated_controller.cpp17
-rw-r--r--src/core/hid/hid_core.cpp5
-rw-r--r--src/core/hid/hid_types.h80
-rw-r--r--src/core/hid/input_interpreter.cpp4
-rw-r--r--src/core/hid/input_interpreter.h4
-rw-r--r--src/core/hle/service/friend/friend.cpp13
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.cpp42
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.h43
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp10
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h6
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp54
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h6
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp10
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h6
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp11
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h6
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp586
-rw-r--r--src/core/hle/service/hid/controllers/npad.h126
-rw-r--r--src/core/hle/service/hid/controllers/palma.cpp86
-rw-r--r--src/core/hle/service/hid/controllers/palma.h8
-rw-r--r--src/core/hle/service/hid/controllers/seven_six_axis.cpp (renamed from src/core/hle/service/hid/controllers/console_sixaxis.cpp)38
-rw-r--r--src/core/hle/service/hid/controllers/seven_six_axis.h (renamed from src/core/hle/service/hid/controllers/console_sixaxis.h)31
-rw-r--r--src/core/hle/service/hid/controllers/six_axis.cpp413
-rw-r--r--src/core/hle/service/hid/controllers/six_axis.h111
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp11
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h6
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp11
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h6
-rw-r--r--src/core/hle/service/hid/hid_server.cpp437
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp424
-rw-r--r--src/core/hle/service/hid/hid_util.h146
-rw-r--r--src/core/hle/service/hid/irs.cpp5
-rw-r--r--src/core/hle/service/hid/resource_manager.cpp155
-rw-r--r--src/core/hle/service/hid/resource_manager.h119
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp3
-rw-r--r--src/core/memory/cheat_engine.cpp5
-rw-r--r--src/frontend_common/CMakeLists.txt10
-rw-r--r--src/frontend_common/config.cpp1008
-rw-r--r--src/frontend_common/config.h210
-rw-r--r--src/video_core/CMakeLists.txt4
-rw-r--r--src/video_core/host1x/codecs/codec.cpp329
-rw-r--r--src/video_core/host1x/codecs/codec.h39
-rw-r--r--src/video_core/host1x/codecs/h264.cpp4
-rw-r--r--src/video_core/host1x/codecs/h264.h1
-rw-r--r--src/video_core/host1x/ffmpeg/ffmpeg.cpp419
-rw-r--r--src/video_core/host1x/ffmpeg/ffmpeg.h213
-rw-r--r--src/video_core/host1x/nvdec.cpp2
-rw-r--r--src/video_core/host1x/nvdec.h2
-rw-r--r--src/video_core/host1x/vic.cpp62
-rw-r--r--src/video_core/host1x/vic.h4
-rw-r--r--src/video_core/query_cache/query_cache.h2
-rw-r--r--src/yuzu/CMakeLists.txt57
-rw-r--r--src/yuzu/configuration/config.cpp1309
-rw-r--r--src/yuzu/configuration/config.h179
-rw-r--r--src/yuzu/configuration/configure_camera.cpp2
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp1
-rw-r--r--src/yuzu/configuration/configure_hotkeys.cpp36
-rw-r--r--src/yuzu/configuration/configure_input_per_game.cpp6
-rw-r--r--src/yuzu/configuration/configure_input_per_game.h5
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp11
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp7
-rw-r--r--src/yuzu/configuration/configure_per_game.h5
-rw-r--r--src/yuzu/configuration/configure_per_game_addons.cpp1
-rw-r--r--src/yuzu/configuration/configure_ringcon.cpp4
-rw-r--r--src/yuzu/configuration/configure_system.cpp1
-rw-r--r--src/yuzu/configuration/configure_touchscreen_advanced.cpp2
-rw-r--r--src/yuzu/configuration/configure_ui.cpp7
-rw-r--r--src/yuzu/configuration/input_profiles.cpp10
-rw-r--r--src/yuzu/configuration/input_profiles.h4
-rw-r--r--src/yuzu/configuration/qt_config.cpp549
-rw-r--r--src/yuzu/configuration/qt_config.h55
-rw-r--r--src/yuzu/configuration/shared_translation.cpp517
-rw-r--r--src/yuzu/configuration/shared_translation.h43
-rw-r--r--src/yuzu/configuration/shared_widget.cpp4
-rw-r--r--src/yuzu/debugger/wait_tree.cpp6
-rw-r--r--src/yuzu/game_list.cpp7
-rw-r--r--src/yuzu/game_list_p.h8
-rw-r--r--src/yuzu/game_list_worker.cpp18
-rw-r--r--src/yuzu/hotkeys.cpp28
-rw-r--r--src/yuzu/hotkeys.h16
-rw-r--r--src/yuzu/main.cpp112
-rw-r--r--src/yuzu/main.h7
-rw-r--r--src/yuzu/uisettings.cpp65
-rw-r--r--src/yuzu/uisettings.h79
-rw-r--r--src/yuzu_cmd/CMakeLists.txt9
-rw-r--r--src/yuzu_cmd/config.cpp279
-rw-r--r--src/yuzu_cmd/config.h38
-rw-r--r--src/yuzu_cmd/default_ini.h553
-rw-r--r--src/yuzu_cmd/sdl_config.cpp257
-rw-r--r--src/yuzu_cmd/sdl_config.h49
-rw-r--r--src/yuzu_cmd/yuzu.cpp5
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 @@
4[submodule "enet"] 4[submodule "enet"]
5 path = externals/enet 5 path = externals/enet
6 url = https://github.com/lsalzman/enet.git 6 url = https://github.com/lsalzman/enet.git
7[submodule "inih"]
8 path = externals/inih/inih
9 url = https://github.com/benhoyt/inih.git
10[submodule "cubeb"] 7[submodule "cubeb"]
11 path = externals/cubeb 8 path = externals/cubeb
12 url = https://github.com/mozilla/cubeb.git 9 url = https://github.com/mozilla/cubeb.git
@@ -61,3 +58,6 @@
61[submodule "breakpad"] 58[submodule "breakpad"]
62 path = externals/breakpad 59 path = externals/breakpad
63 url = https://github.com/yuzu-emu/breakpad.git 60 url = https://github.com/yuzu-emu/breakpad.git
61[submodule "simpleini"]
62 path = externals/simpleini
63 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)
285find_package(Boost 1.79.0 REQUIRED context) 285find_package(Boost 1.79.0 REQUIRED context)
286find_package(enet 1.3 MODULE) 286find_package(enet 1.3 MODULE)
287find_package(fmt 9 REQUIRED) 287find_package(fmt 9 REQUIRED)
288find_package(inih 52 MODULE COMPONENTS INIReader)
289find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle) 288find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle)
290find_package(lz4 REQUIRED) 289find_package(lz4 REQUIRED)
291find_package(nlohmann_json 3.8 REQUIRED) 290find_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 @@
1# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
2#
3# SPDX-License-Identifier: GPL-3.0-or-later
4
5find_package(PkgConfig QUIET)
6pkg_search_module(INIH QUIET IMPORTED_TARGET inih)
7if (INIReader IN_LIST inih_FIND_COMPONENTS)
8 pkg_search_module(INIREADER QUIET IMPORTED_TARGET INIReader)
9 if (INIREADER_FOUND)
10 set(inih_INIReader_FOUND TRUE)
11 endif()
12endif()
13
14include(FindPackageHandleStandardArgs)
15find_package_handle_standard_args(inih
16 REQUIRED_VARS INIH_LINK_LIBRARIES
17 VERSION_VAR INIH_VERSION
18 HANDLE_COMPONENTS
19)
20
21if (inih_FOUND AND NOT TARGET inih::inih)
22 add_library(inih::inih ALIAS PkgConfig::INIH)
23endif()
24
25if (inih_FOUND AND inih_INIReader_FOUND AND NOT TARGET inih::INIReader)
26 add_library(inih::INIReader ALIAS PkgConfig::INIREADER)
27endif()
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
6source_file = en.ts 6source_file = en.ts
7source_lang = en 7source_lang = en
8type = QT 8type = QT
9
10[o:yuzu-emulator:p:yuzu:r:yuzu-android]
11file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml
12source_file = ../../src/android/app/src/main/res/values/strings.xml
13type = 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()
34# Glad 34# Glad
35add_subdirectory(glad) 35add_subdirectory(glad)
36 36
37# inih
38if (NOT TARGET inih::INIReader)
39 add_subdirectory(inih)
40endif()
41
42# mbedtls 37# mbedtls
43add_subdirectory(mbedtls) 38add_subdirectory(mbedtls)
44target_include_directories(mbedtls PUBLIC ./mbedtls/include) 39target_include_directories(mbedtls PUBLIC ./mbedtls/include)
@@ -295,3 +290,6 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
295 target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB) 290 target_link_libraries(dump_syms PRIVATE libbreakpad_client ZLIB::ZLIB)
296 endif() 291 endif()
297endif() 292endif()
293
294# SimpleIni
295add_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 @@
1# SPDX-FileCopyrightText: 2014 Gui Andrade <admin@archshift.com>
2# SPDX-License-Identifier: GPL-2.0-or-later
3
4add_library(inih
5 inih/ini.c
6 inih/ini.h
7 inih/cpp/INIReader.cpp
8 inih/cpp/INIReader.h
9)
10
11create_target_directory_groups(inih)
12target_include_directories(inih INTERFACE inih/cpp)
13add_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)
187add_subdirectory(video_core) 187add_subdirectory(video_core)
188add_subdirectory(network) 188add_subdirectory(network)
189add_subdirectory(input_common) 189add_subdirectory(input_common)
190add_subdirectory(frontend_common)
190add_subdirectory(shader_recompiler) 191add_subdirectory(shader_recompiler)
191 192
192if (YUZU_ROOM) 193if (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 {
219 implementation("io.coil-kt:coil:2.2.2") 219 implementation("io.coil-kt:coil:2.2.2")
220 implementation("androidx.core:core-splashscreen:1.0.1") 220 implementation("androidx.core:core-splashscreen:1.0.1")
221 implementation("androidx.window:window:1.2.0-beta03") 221 implementation("androidx.window:window:1.2.0-beta03")
222 implementation("org.ini4j:ini4j:0.5.4")
223 implementation("androidx.constraintlayout:constraintlayout:2.1.4") 222 implementation("androidx.constraintlayout:constraintlayout:2.1.4")
224 implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") 223 implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
225 implementation("androidx.navigation:navigation-fragment-ktx:2.7.4") 224 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 {
230 */ 230 */
231 external fun onTouchReleased(finger_id: Int) 231 external fun onTouchReleased(finger_id: Int)
232 232
233 external fun reloadSettings()
234
235 external fun initGameIni(gameID: String?) 233 external fun initGameIni(gameID: String?)
236 234
237 external fun setAppDirectory(directory: String) 235 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
7import android.widget.Toast 7import android.widget.Toast
8import org.yuzu.yuzu_emu.R 8import org.yuzu.yuzu_emu.R
9import org.yuzu.yuzu_emu.YuzuApplication 9import org.yuzu.yuzu_emu.YuzuApplication
10import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 10import org.yuzu.yuzu_emu.utils.NativeConfig
11 11
12object Settings { 12object Settings {
13 private val context get() = YuzuApplication.appContext 13 private val context get() = YuzuApplication.appContext
@@ -19,7 +19,7 @@ object Settings {
19 context.getString(R.string.ini_saved), 19 context.getString(R.string.ini_saved),
20 Toast.LENGTH_SHORT 20 Toast.LENGTH_SHORT
21 ).show() 21 ).show()
22 SettingsFile.saveFile(SettingsFile.FILE_NAME_CONFIG) 22 NativeConfig.saveSettings()
23 } else { 23 } else {
24 // TODO: Save custom game settings 24 // TODO: Save custom game settings
25 Toast.makeText( 25 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
21import com.google.android.material.color.MaterialColors 21import com.google.android.material.color.MaterialColors
22import kotlinx.coroutines.flow.collectLatest 22import kotlinx.coroutines.flow.collectLatest
23import kotlinx.coroutines.launch 23import kotlinx.coroutines.launch
24import org.yuzu.yuzu_emu.NativeLibrary
25import java.io.IOException 24import java.io.IOException
26import org.yuzu.yuzu_emu.R 25import org.yuzu.yuzu_emu.R
27import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding 26import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding
@@ -165,11 +164,12 @@ class SettingsActivity : AppCompatActivity() {
165 settingsViewModel.shouldSave = false 164 settingsViewModel.shouldSave = false
166 165
167 // Delete settings file because the user may have changed values that do not exist in the UI 166 // Delete settings file because the user may have changed values that do not exist in the UI
167 NativeConfig.unloadConfig()
168 val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG) 168 val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG)
169 if (!settingsFile.delete()) { 169 if (!settingsFile.delete()) {
170 throw IOException("Failed to delete $settingsFile") 170 throw IOException("Failed to delete $settingsFile")
171 } 171 }
172 NativeLibrary.reloadSettings() 172 NativeConfig.initializeConfig()
173 173
174 Toast.makeText( 174 Toast.makeText(
175 applicationContext, 175 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 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.utils 4package org.yuzu.yuzu_emu.features.settings.utils
5 5
6import android.widget.Toast
7import java.io.* 6import java.io.*
8import org.ini4j.Wini
9import org.yuzu.yuzu_emu.R
10import org.yuzu.yuzu_emu.YuzuApplication
11import org.yuzu.yuzu_emu.features.settings.model.*
12import org.yuzu.yuzu_emu.utils.DirectoryInitialization 7import org.yuzu.yuzu_emu.utils.DirectoryInitialization
13import org.yuzu.yuzu_emu.utils.Log
14import org.yuzu.yuzu_emu.utils.NativeConfig
15 8
16/** 9/**
17 * Contains static methods for interacting with .ini files in which settings are stored. 10 * Contains static methods for interacting with .ini files in which settings are stored.
@@ -19,41 +12,6 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
19object SettingsFile { 12object SettingsFile {
20 const val FILE_NAME_CONFIG = "config" 13 const val FILE_NAME_CONFIG = "config"
21 14
22 /**
23 * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error
24 * telling why it failed.
25 *
26 * @param fileName The target filename without a path or extension.
27 */
28 fun saveFile(fileName: String) {
29 val ini = getSettingsFile(fileName)
30 try {
31 val wini = Wini(ini)
32 for (specificCategory in Settings.Category.values()) {
33 val categoryHeader = NativeConfig.getConfigHeader(specificCategory.ordinal)
34 for (setting in Settings.settingsList) {
35 if (setting.key!!.isEmpty()) continue
36
37 val settingCategoryHeader =
38 NativeConfig.getConfigHeader(setting.category.ordinal)
39 val iniSetting: String? = wini.get(categoryHeader, setting.key)
40 if (iniSetting != null || settingCategoryHeader == categoryHeader) {
41 wini.put(settingCategoryHeader, setting.key, setting.valueAsString)
42 }
43 }
44 }
45 wini.store()
46 } catch (e: IOException) {
47 Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.message)
48 val context = YuzuApplication.appContext
49 Toast.makeText(
50 context,
51 context.getString(R.string.error_saving, fileName, e.message),
52 Toast.LENGTH_SHORT
53 ).show()
54 }
55 }
56
57 fun getSettingsFile(fileName: String): File = 15 fun getSettingsFile(fileName: String): File =
58 File(DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini") 16 File(DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini")
59} 17}
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 {
625 } 625 }
626 626
627 // Clear existing user data 627 // Clear existing user data
628 NativeConfig.unloadConfig()
628 File(DirectoryInitialization.userDirectory!!).deleteRecursively() 629 File(DirectoryInitialization.userDirectory!!).deleteRecursively()
629 630
630 // Copy archive to internal storage 631 // Copy archive to internal storage
@@ -643,6 +644,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
643 644
644 // Reinitialize relevant data 645 // Reinitialize relevant data
645 NativeLibrary.initializeSystem(true) 646 NativeLibrary.initializeSystem(true)
647 NativeConfig.initializeConfig()
646 gamesViewModel.reloadGames(false) 648 gamesViewModel.reloadGames(false)
647 649
648 return@newInstance getString(R.string.user_data_import_success) 650 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 {
16 if (!areDirectoriesReady) { 16 if (!areDirectoriesReady) {
17 initializeInternalStorage() 17 initializeInternalStorage()
18 NativeLibrary.initializeSystem(false) 18 NativeLibrary.initializeSystem(false)
19 NativeConfig.initializeConfig()
19 areDirectoriesReady = true 20 areDirectoriesReady = true
20 } 21 }
21 } 22 }
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 @@
4package org.yuzu.yuzu_emu.utils 4package org.yuzu.yuzu_emu.utils
5 5
6object NativeConfig { 6object NativeConfig {
7 /**
8 * Creates a Config object and opens the emulation config.
9 */
10 @Synchronized
11 external fun initializeConfig()
12
13 /**
14 * Destroys the stored config object. This automatically saves the existing config.
15 */
16 @Synchronized
17 external fun unloadConfig()
18
19 /**
20 * Reads values saved to the config file and saves them.
21 */
22 @Synchronized
23 external fun reloadSettings()
24
25 /**
26 * Saves settings values in memory to disk.
27 */
28 @Synchronized
29 external fun saveSettings()
30
7 external fun getBoolean(key: String, getDefault: Boolean): Boolean 31 external fun getBoolean(key: String, getDefault: Boolean): Boolean
8 external fun setBoolean(key: String, value: Boolean) 32 external fun setBoolean(key: String, value: Boolean)
9 33
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
6 android_common/android_common.h 6 android_common/android_common.h
7 applets/software_keyboard.cpp 7 applets/software_keyboard.cpp
8 applets/software_keyboard.h 8 applets/software_keyboard.h
9 config.cpp
10 config.h
11 default_ini.h
12 emu_window/emu_window.cpp 9 emu_window/emu_window.cpp
13 emu_window/emu_window.h 10 emu_window/emu_window.h
14 id_cache.cpp 11 id_cache.cpp
@@ -16,15 +13,17 @@ add_library(yuzu-android SHARED
16 native.cpp 13 native.cpp
17 native.h 14 native.h
18 native_config.cpp 15 native_config.cpp
19 uisettings.cpp 16 android_settings.cpp
20 game_metadata.cpp 17 game_metadata.cpp
21 native_log.cpp 18 native_log.cpp
19 android_config.cpp
20 android_config.h
22) 21)
23 22
24set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) 23set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
25 24
26target_link_libraries(yuzu-android PRIVATE audio_core common core input_common) 25target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common)
27target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics log) 26target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log)
28if (ARCHITECTURE_arm64) 27if (ARCHITECTURE_arm64)
29 target_link_libraries(yuzu-android PRIVATE adrenotools) 28 target_link_libraries(yuzu-android PRIVATE adrenotools)
30endif() 29endif()
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "android_config.h"
5#include "android_settings.h"
6#include "common/settings_setting.h"
7
8AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_type)
9 : Config(config_type) {
10 Initialize(config_name);
11 if (config_type != ConfigType::InputProfile) {
12 ReadAndroidValues();
13 SaveAndroidValues();
14 }
15}
16
17AndroidConfig::~AndroidConfig() {
18 if (global) {
19 AndroidConfig::SaveAllValues();
20 }
21}
22
23void AndroidConfig::ReloadAllValues() {
24 Reload();
25 ReadAndroidValues();
26 SaveAndroidValues();
27}
28
29void AndroidConfig::SaveAllValues() {
30 Save();
31 SaveAndroidValues();
32}
33
34void AndroidConfig::ReadAndroidValues() {
35 if (global) {
36 ReadAndroidUIValues();
37 }
38}
39
40void AndroidConfig::ReadAndroidUIValues() {
41 BeginGroup(Settings::TranslateCategory(Settings::Category::Android));
42
43 ReadCategory(Settings::Category::Android);
44
45 EndGroup();
46}
47
48void AndroidConfig::SaveAndroidValues() {
49 if (global) {
50 SaveAndroidUIValues();
51 }
52
53 WriteToIni();
54}
55
56void AndroidConfig::SaveAndroidUIValues() {
57 BeginGroup(Settings::TranslateCategory(Settings::Category::Android));
58
59 WriteCategory(Settings::Category::Android);
60
61 EndGroup();
62}
63
64std::vector<Settings::BasicSetting*>& AndroidConfig::FindRelevantList(Settings::Category category) {
65 auto& map = Settings::values.linkage.by_category;
66 if (map.contains(category)) {
67 return Settings::values.linkage.by_category[category];
68 }
69 return AndroidSettings::values.linkage.by_category[category];
70}
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "frontend_common/config.h"
7
8class AndroidConfig final : public Config {
9public:
10 explicit AndroidConfig(const std::string& config_name = "config",
11 ConfigType config_type = ConfigType::GlobalConfig);
12 ~AndroidConfig() override;
13
14 void ReloadAllValues() override;
15 void SaveAllValues() override;
16
17protected:
18 void ReadAndroidValues();
19 void ReadAndroidUIValues();
20 void ReadHidbusValues() override {}
21 void ReadDebugControlValues() override {}
22 void ReadPathValues() override {}
23 void ReadShortcutValues() override {}
24 void ReadUIValues() override {}
25 void ReadUIGamelistValues() override {}
26 void ReadUILayoutValues() override {}
27 void ReadMultiplayerValues() override {}
28
29 void SaveAndroidValues();
30 void SaveAndroidUIValues();
31 void SaveHidbusValues() override {}
32 void SaveDebugControlValues() override {}
33 void SavePathValues() override {}
34 void SaveShortcutValues() override {}
35 void SaveUIValues() override {}
36 void SaveUIGamelistValues() override {}
37 void SaveUILayoutValues() override {}
38 void SaveMultiplayerValues() override {}
39
40 std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
41};
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "uisettings.h" 4#include "android_settings.h"
5 5
6namespace AndroidSettings { 6namespace AndroidSettings {
7 7
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <memory>
5#include <optional>
6#include <sstream>
7
8#include <INIReader.h>
9#include "common/fs/file.h"
10#include "common/fs/fs.h"
11#include "common/fs/path_util.h"
12#include "common/logging/log.h"
13#include "common/settings.h"
14#include "common/settings_enums.h"
15#include "core/hle/service/acc/profile_manager.h"
16#include "input_common/main.h"
17#include "jni/config.h"
18#include "jni/default_ini.h"
19#include "uisettings.h"
20
21namespace FS = Common::FS;
22
23Config::Config(const std::string& config_name, ConfigType config_type)
24 : type(config_type), global{config_type == ConfigType::GlobalConfig} {
25 Initialize(config_name);
26}
27
28Config::~Config() = default;
29
30bool Config::LoadINI(const std::string& default_contents, bool retry) {
31 void(FS::CreateParentDir(config_loc));
32 config = std::make_unique<INIReader>(FS::PathToUTF8String(config_loc));
33 const auto config_loc_str = FS::PathToUTF8String(config_loc);
34 if (config->ParseError() < 0) {
35 if (retry) {
36 LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...",
37 config_loc_str);
38
39 void(FS::CreateParentDir(config_loc));
40 void(FS::WriteStringToFile(config_loc, FS::FileType::TextFile, default_contents));
41
42 config = std::make_unique<INIReader>(config_loc_str);
43
44 return LoadINI(default_contents, false);
45 }
46 LOG_ERROR(Config, "Failed.");
47 return false;
48 }
49 LOG_INFO(Config, "Successfully loaded {}", config_loc_str);
50 return true;
51}
52
53template <>
54void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
55 std::string setting_value = config->Get(group, setting.GetLabel(), setting.GetDefault());
56 if (setting_value.empty()) {
57 setting_value = setting.GetDefault();
58 }
59 setting = std::move(setting_value);
60}
61
62template <>
63void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
64 setting = config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
65}
66
67template <typename Type, bool ranged>
68void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
69 setting = static_cast<Type>(
70 config->GetInteger(group, setting.GetLabel(), static_cast<long>(setting.GetDefault())));
71}
72
73void Config::ReadValues() {
74 ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
75 ReadSetting("ControlsGeneral", Settings::values.touch_device);
76 ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled);
77 ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled);
78 ReadSetting("ControlsGeneral", Settings::values.vibration_enabled);
79 ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations);
80 ReadSetting("ControlsGeneral", Settings::values.motion_enabled);
81 Settings::values.touchscreen.enabled =
82 config->GetBoolean("ControlsGeneral", "touch_enabled", true);
83 Settings::values.touchscreen.rotation_angle =
84 config->GetInteger("ControlsGeneral", "touch_angle", 0);
85 Settings::values.touchscreen.diameter_x =
86 config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
87 Settings::values.touchscreen.diameter_y =
88 config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
89
90 int num_touch_from_button_maps =
91 config->GetInteger("ControlsGeneral", "touch_from_button_map", 0);
92 if (num_touch_from_button_maps > 0) {
93 for (int i = 0; i < num_touch_from_button_maps; ++i) {
94 Settings::TouchFromButtonMap map;
95 map.name = config->Get("ControlsGeneral",
96 std::string("touch_from_button_maps_") + std::to_string(i) +
97 std::string("_name"),
98 "default");
99 const int num_touch_maps = config->GetInteger(
100 "ControlsGeneral",
101 std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"),
102 0);
103 map.buttons.reserve(num_touch_maps);
104
105 for (int j = 0; j < num_touch_maps; ++j) {
106 std::string touch_mapping =
107 config->Get("ControlsGeneral",
108 std::string("touch_from_button_maps_") + std::to_string(i) +
109 std::string("_bind_") + std::to_string(j),
110 "");
111 map.buttons.emplace_back(std::move(touch_mapping));
112 }
113
114 Settings::values.touch_from_button_maps.emplace_back(std::move(map));
115 }
116 } else {
117 Settings::values.touch_from_button_maps.emplace_back(
118 Settings::TouchFromButtonMap{"default", {}});
119 num_touch_from_button_maps = 1;
120 }
121 Settings::values.touch_from_button_map_index = std::clamp(
122 Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
123
124 ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
125
126 // Data Storage
127 ReadSetting("Data Storage", Settings::values.use_virtual_sd);
128 FS::SetYuzuPath(FS::YuzuPath::NANDDir,
129 config->Get("Data Storage", "nand_directory",
130 FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
131 FS::SetYuzuPath(FS::YuzuPath::SDMCDir,
132 config->Get("Data Storage", "sdmc_directory",
133 FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
134 FS::SetYuzuPath(FS::YuzuPath::LoadDir,
135 config->Get("Data Storage", "load_directory",
136 FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
137 FS::SetYuzuPath(FS::YuzuPath::DumpDir,
138 config->Get("Data Storage", "dump_directory",
139 FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
140 ReadSetting("Data Storage", Settings::values.gamecard_inserted);
141 ReadSetting("Data Storage", Settings::values.gamecard_current_game);
142 ReadSetting("Data Storage", Settings::values.gamecard_path);
143
144 // System
145 ReadSetting("System", Settings::values.current_user);
146 Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0,
147 Service::Account::MAX_USERS - 1);
148
149 // Disable docked mode by default on Android
150 Settings::values.use_docked_mode.SetValue(config->GetBoolean("System", "use_docked_mode", false)
151 ? Settings::ConsoleMode::Docked
152 : Settings::ConsoleMode::Handheld);
153
154 const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false);
155 if (rng_seed_enabled) {
156 Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0));
157 } else {
158 Settings::values.rng_seed.SetValue(0);
159 }
160 Settings::values.rng_seed_enabled.SetValue(rng_seed_enabled);
161
162 const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false);
163 if (custom_rtc_enabled) {
164 Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0);
165 } else {
166 Settings::values.custom_rtc = 0;
167 }
168 Settings::values.custom_rtc_enabled = custom_rtc_enabled;
169
170 ReadSetting("System", Settings::values.language_index);
171 ReadSetting("System", Settings::values.region_index);
172 ReadSetting("System", Settings::values.time_zone_index);
173 ReadSetting("System", Settings::values.sound_index);
174
175 // Core
176 ReadSetting("Core", Settings::values.use_multi_core);
177 ReadSetting("Core", Settings::values.memory_layout_mode);
178
179 // Cpu
180 ReadSetting("Cpu", Settings::values.cpu_accuracy);
181 ReadSetting("Cpu", Settings::values.cpu_debug_mode);
182 ReadSetting("Cpu", Settings::values.cpuopt_page_tables);
183 ReadSetting("Cpu", Settings::values.cpuopt_block_linking);
184 ReadSetting("Cpu", Settings::values.cpuopt_return_stack_buffer);
185 ReadSetting("Cpu", Settings::values.cpuopt_fast_dispatcher);
186 ReadSetting("Cpu", Settings::values.cpuopt_context_elimination);
187 ReadSetting("Cpu", Settings::values.cpuopt_const_prop);
188 ReadSetting("Cpu", Settings::values.cpuopt_misc_ir);
189 ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks);
190 ReadSetting("Cpu", Settings::values.cpuopt_fastmem);
191 ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives);
192 ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives);
193 ReadSetting("Cpu", Settings::values.cpuopt_ignore_memory_aborts);
194 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma);
195 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error);
196 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr);
197 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan);
198 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check);
199 ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor);
200
201 // Renderer
202 ReadSetting("Renderer", Settings::values.renderer_backend);
203 ReadSetting("Renderer", Settings::values.renderer_debug);
204 ReadSetting("Renderer", Settings::values.renderer_shader_feedback);
205 ReadSetting("Renderer", Settings::values.enable_nsight_aftermath);
206 ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks);
207 ReadSetting("Renderer", Settings::values.vulkan_device);
208
209 ReadSetting("Renderer", Settings::values.resolution_setup);
210 ReadSetting("Renderer", Settings::values.scaling_filter);
211 ReadSetting("Renderer", Settings::values.fsr_sharpening_slider);
212 ReadSetting("Renderer", Settings::values.anti_aliasing);
213 ReadSetting("Renderer", Settings::values.fullscreen_mode);
214 ReadSetting("Renderer", Settings::values.aspect_ratio);
215 ReadSetting("Renderer", Settings::values.max_anisotropy);
216 ReadSetting("Renderer", Settings::values.use_speed_limit);
217 ReadSetting("Renderer", Settings::values.speed_limit);
218 ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
219 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
220 ReadSetting("Renderer", Settings::values.vsync_mode);
221 ReadSetting("Renderer", Settings::values.shader_backend);
222 ReadSetting("Renderer", Settings::values.use_asynchronous_shaders);
223 ReadSetting("Renderer", Settings::values.nvdec_emulation);
224 ReadSetting("Renderer", Settings::values.use_fast_gpu_time);
225 ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache);
226
227 ReadSetting("Renderer", Settings::values.bg_red);
228 ReadSetting("Renderer", Settings::values.bg_green);
229 ReadSetting("Renderer", Settings::values.bg_blue);
230
231 // Use GPU accuracy normal by default on Android
232 Settings::values.gpu_accuracy = static_cast<Settings::GpuAccuracy>(config->GetInteger(
233 "Renderer", "gpu_accuracy", static_cast<u32>(Settings::GpuAccuracy::Normal)));
234
235 // Use GPU default anisotropic filtering on Android
236 Settings::values.max_anisotropy =
237 static_cast<Settings::AnisotropyMode>(config->GetInteger("Renderer", "max_anisotropy", 1));
238
239 // Disable ASTC compute by default on Android
240 Settings::values.accelerate_astc.SetValue(
241 config->GetBoolean("Renderer", "accelerate_astc", false) ? Settings::AstcDecodeMode::Gpu
242 : Settings::AstcDecodeMode::Cpu);
243
244 // Enable asynchronous presentation by default on Android
245 Settings::values.async_presentation =
246 config->GetBoolean("Renderer", "async_presentation", true);
247
248 // Disable force_max_clock by default on Android
249 Settings::values.renderer_force_max_clock =
250 config->GetBoolean("Renderer", "force_max_clock", false);
251
252 // Disable use_reactive_flushing by default on Android
253 Settings::values.use_reactive_flushing =
254 config->GetBoolean("Renderer", "use_reactive_flushing", false);
255
256 // Audio
257 ReadSetting("Audio", Settings::values.sink_id);
258 ReadSetting("Audio", Settings::values.audio_output_device_id);
259 ReadSetting("Audio", Settings::values.volume);
260
261 // Miscellaneous
262 // log_filter has a different default here than from common
263 Settings::values.log_filter = "*:Info";
264 ReadSetting("Miscellaneous", Settings::values.use_dev_keys);
265
266 // Debugging
267 Settings::values.record_frame_times =
268 config->GetBoolean("Debugging", "record_frame_times", false);
269 ReadSetting("Debugging", Settings::values.dump_exefs);
270 ReadSetting("Debugging", Settings::values.dump_nso);
271 ReadSetting("Debugging", Settings::values.enable_fs_access_log);
272 ReadSetting("Debugging", Settings::values.reporting_services);
273 ReadSetting("Debugging", Settings::values.quest_flag);
274 ReadSetting("Debugging", Settings::values.use_debug_asserts);
275 ReadSetting("Debugging", Settings::values.use_auto_stub);
276 ReadSetting("Debugging", Settings::values.disable_macro_jit);
277 ReadSetting("Debugging", Settings::values.disable_macro_hle);
278 ReadSetting("Debugging", Settings::values.use_gdbstub);
279 ReadSetting("Debugging", Settings::values.gdbstub_port);
280
281 const auto title_list = config->Get("AddOns", "title_ids", "");
282 std::stringstream ss(title_list);
283 std::string line;
284 while (std::getline(ss, line, '|')) {
285 const auto title_id = std::strtoul(line.c_str(), nullptr, 16);
286 const auto disabled_list = config->Get("AddOns", "disabled_" + line, "");
287
288 std::stringstream inner_ss(disabled_list);
289 std::string inner_line;
290 std::vector<std::string> out;
291 while (std::getline(inner_ss, inner_line, '|')) {
292 out.push_back(inner_line);
293 }
294
295 Settings::values.disabled_addons.insert_or_assign(title_id, out);
296 }
297
298 // Web Service
299 ReadSetting("WebService", Settings::values.enable_telemetry);
300 ReadSetting("WebService", Settings::values.web_api_url);
301 ReadSetting("WebService", Settings::values.yuzu_username);
302 ReadSetting("WebService", Settings::values.yuzu_token);
303
304 // Network
305 ReadSetting("Network", Settings::values.network_interface);
306
307 // Android
308 ReadSetting("Android", AndroidSettings::values.picture_in_picture);
309 ReadSetting("Android", AndroidSettings::values.screen_layout);
310}
311
312void Config::Initialize(const std::string& config_name) {
313 const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir);
314 const auto config_file = fmt::format("{}.ini", config_name);
315
316 switch (type) {
317 case ConfigType::GlobalConfig:
318 config_loc = FS::PathToUTF8String(fs_config_loc / config_file);
319 break;
320 case ConfigType::PerGameConfig:
321 config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file));
322 break;
323 case ConfigType::InputProfile:
324 config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file);
325 LoadINI(DefaultINI::android_config_file);
326 return;
327 }
328 LoadINI(DefaultINI::android_config_file);
329 ReadValues();
330}
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <filesystem>
7#include <memory>
8#include <optional>
9#include <string>
10
11#include "common/settings.h"
12
13class INIReader;
14
15class Config {
16 bool LoadINI(const std::string& default_contents = "", bool retry = true);
17
18public:
19 enum class ConfigType {
20 GlobalConfig,
21 PerGameConfig,
22 InputProfile,
23 };
24
25 explicit Config(const std::string& config_name = "config",
26 ConfigType config_type = ConfigType::GlobalConfig);
27 ~Config();
28
29 void Initialize(const std::string& config_name);
30
31private:
32 /**
33 * Applies a value read from the config to a Setting.
34 *
35 * @param group The name of the INI group
36 * @param setting The yuzu setting to modify
37 */
38 template <typename Type, bool ranged>
39 void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
40
41 void ReadValues();
42
43 const ConfigType type;
44 std::unique_ptr<INIReader> config;
45 std::string config_loc;
46 const bool global;
47};
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6namespace DefaultINI {
7
8const char* android_config_file = R"(
9
10[ControlsP0]
11# The input devices and parameters for each Switch native input
12# The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ...
13# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..."
14# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values
15
16# Indicates if this player should be connected at boot
17connected=
18
19# for button input, the following devices are available:
20# - "keyboard" (default) for keyboard input. Required parameters:
21# - "code": the code of the key to bind
22# - "sdl" for joystick input using SDL. Required parameters:
23# - "guid": SDL identification GUID of the joystick
24# - "port": the index of the joystick to bind
25# - "button"(optional): the index of the button to bind
26# - "hat"(optional): the index of the hat to bind as direction buttons
27# - "axis"(optional): the index of the axis to bind
28# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right"
29# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
30# triggered if the axis value crosses
31# - "direction"(only used for axis): "+" means the button is triggered when the axis value
32# is greater than the threshold; "-" means the button is triggered when the axis value
33# is smaller than the threshold
34button_a=
35button_b=
36button_x=
37button_y=
38button_lstick=
39button_rstick=
40button_l=
41button_r=
42button_zl=
43button_zr=
44button_plus=
45button_minus=
46button_dleft=
47button_dup=
48button_dright=
49button_ddown=
50button_lstick_left=
51button_lstick_up=
52button_lstick_right=
53button_lstick_down=
54button_sl=
55button_sr=
56button_home=
57button_screenshot=
58
59# for analog input, the following devices are available:
60# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters:
61# - "up", "down", "left", "right": sub-devices for each direction.
62# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00"
63# - "modifier": sub-devices as a modifier.
64# - "modifier_scale": a float number representing the applied modifier scale to the analog input.
65# Must be in range of 0.0-1.0. Defaults to 0.5
66# - "sdl" for joystick input using SDL. Required parameters:
67# - "guid": SDL identification GUID of the joystick
68# - "port": the index of the joystick to bind
69# - "axis_x": the index of the axis to bind as x-axis (default to 0)
70# - "axis_y": the index of the axis to bind as y-axis (default to 1)
71lstick=
72rstick=
73
74# for motion input, the following devices are available:
75# - "keyboard" (default) for emulating random motion input from buttons. Required parameters:
76# - "code": the code of the key to bind
77# - "sdl" for motion input using SDL. Required parameters:
78# - "guid": SDL identification GUID of the joystick
79# - "port": the index of the joystick to bind
80# - "motion": the index of the motion sensor to bind
81# - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters:
82# - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001"
83# - "port": the port of the cemu hook server
84# - "pad": the index of the joystick
85# - "motion": the index of the motion sensor of the joystick to bind
86motionleft=
87motionright=
88
89[ControlsGeneral]
90# To use the debug_pad, prepend `debug_pad_` before each button setting above.
91# i.e. debug_pad_button_a=
92
93# Enable debug pad inputs to the guest
94# 0 (default): Disabled, 1: Enabled
95debug_pad_enabled =
96
97# Whether to enable or disable vibration
98# 0: Disabled, 1 (default): Enabled
99vibration_enabled=
100
101# Whether to enable or disable accurate vibrations
102# 0 (default): Disabled, 1: Enabled
103enable_accurate_vibrations=
104
105# Enables controller motion inputs
106# 0: Disabled, 1 (default): Enabled
107motion_enabled =
108
109# Defines the udp device's touch screen coordinate system for cemuhookudp devices
110# - "min_x", "min_y", "max_x", "max_y"
111touch_device=
112
113# for mapping buttons to touch inputs.
114#touch_from_button_map=1
115#touch_from_button_maps_0_name=default
116#touch_from_button_maps_0_count=2
117#touch_from_button_maps_0_bind_0=foo
118#touch_from_button_maps_0_bind_1=bar
119# etc.
120
121# List of Cemuhook UDP servers, delimited by ','.
122# Default: 127.0.0.1:26760
123# Example: 127.0.0.1:26760,123.4.5.67:26761
124udp_input_servers =
125
126# Enable controlling an axis via a mouse input.
127# 0 (default): Off, 1: On
128mouse_panning =
129
130# Set mouse sensitivity.
131# Default: 1.0
132mouse_panning_sensitivity =
133
134# Emulate an analog control stick from keyboard inputs.
135# 0 (default): Disabled, 1: Enabled
136emulate_analog_keyboard =
137
138# Enable mouse inputs to the guest
139# 0 (default): Disabled, 1: Enabled
140mouse_enabled =
141
142# Enable keyboard inputs to the guest
143# 0 (default): Disabled, 1: Enabled
144keyboard_enabled =
145
146[Core]
147# Whether to use multi-core for CPU emulation
148# 0: Disabled, 1 (default): Enabled
149use_multi_core =
150
151# Enable unsafe extended guest system memory layout (8GB DRAM)
152# 0 (default): Disabled, 1: Enabled
153use_unsafe_extended_memory_layout =
154
155[Cpu]
156# Adjusts various optimizations.
157# Auto-select mode enables choice unsafe optimizations.
158# Accurate enables only safe optimizations.
159# Unsafe allows any unsafe optimizations.
160# 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations
161cpu_accuracy =
162
163# Allow disabling safe optimizations.
164# 0 (default): Disabled, 1: Enabled
165cpu_debug_mode =
166
167# Enable inline page tables optimization (faster guest memory access)
168# 0: Disabled, 1 (default): Enabled
169cpuopt_page_tables =
170
171# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
172# 0: Disabled, 1 (default): Enabled
173cpuopt_block_linking =
174
175# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
176# 0: Disabled, 1 (default): Enabled
177cpuopt_return_stack_buffer =
178
179# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
180# 0: Disabled, 1 (default): Enabled
181cpuopt_fast_dispatcher =
182
183# Enable context elimination CPU Optimization (reduce host memory use for guest context)
184# 0: Disabled, 1 (default): Enabled
185cpuopt_context_elimination =
186
187# Enable constant propagation CPU optimization (basic IR optimization)
188# 0: Disabled, 1 (default): Enabled
189cpuopt_const_prop =
190
191# Enable miscellaneous CPU optimizations (basic IR optimization)
192# 0: Disabled, 1 (default): Enabled
193cpuopt_misc_ir =
194
195# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
196# 0: Disabled, 1 (default): Enabled
197cpuopt_reduce_misalign_checks =
198
199# Enable Host MMU Emulation (faster guest memory access)
200# 0: Disabled, 1 (default): Enabled
201cpuopt_fastmem =
202
203# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access)
204# 0: Disabled, 1 (default): Enabled
205cpuopt_fastmem_exclusives =
206
207# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access)
208# 0: Disabled, 1 (default): Enabled
209cpuopt_recompile_exclusives =
210
211# Enable optimization to ignore invalid memory accesses (faster guest memory access)
212# 0: Disabled, 1 (default): Enabled
213cpuopt_ignore_memory_aborts =
214
215# Enable unfuse FMA (improve performance on CPUs without FMA)
216# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
217# 0: Disabled, 1 (default): Enabled
218cpuopt_unsafe_unfuse_fma =
219
220# Enable faster FRSQRTE and FRECPE
221# Only enabled if cpu_accuracy is set to Unsafe.
222# 0: Disabled, 1 (default): Enabled
223cpuopt_unsafe_reduce_fp_error =
224
225# Enable faster ASIMD instructions (32 bits only)
226# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
227# 0: Disabled, 1 (default): Enabled
228cpuopt_unsafe_ignore_standard_fpcr =
229
230# Enable inaccurate NaN handling
231# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
232# 0: Disabled, 1 (default): Enabled
233cpuopt_unsafe_inaccurate_nan =
234
235# Disable address space checks (64 bits only)
236# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
237# 0: Disabled, 1 (default): Enabled
238cpuopt_unsafe_fastmem_check =
239
240# Enable faster exclusive instructions
241# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
242# 0: Disabled, 1 (default): Enabled
243cpuopt_unsafe_ignore_global_monitor =
244
245[Renderer]
246# Which backend API to use.
247# 0: OpenGL (unsupported), 1 (default): Vulkan, 2: Null
248backend =
249
250# Whether to enable asynchronous presentation (Vulkan only)
251# 0: Off, 1 (default): On
252async_presentation =
253
254# Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).
255# 0 (default): Disabled, 1: Enabled
256force_max_clock =
257
258# Enable graphics API debugging mode.
259# 0 (default): Disabled, 1: Enabled
260debug =
261
262# Enable shader feedback.
263# 0 (default): Disabled, 1: Enabled
264renderer_shader_feedback =
265
266# Enable Nsight Aftermath crash dumps
267# 0 (default): Disabled, 1: Enabled
268nsight_aftermath =
269
270# Disable shader loop safety checks, executing the shader without loop logic changes
271# 0 (default): Disabled, 1: Enabled
272disable_shader_loop_safety_checks =
273
274# Which Vulkan physical device to use (defaults to 0)
275vulkan_device =
276
277# 0: 0.5x (360p/540p) [EXPERIMENTAL]
278# 1: 0.75x (540p/810p) [EXPERIMENTAL]
279# 2 (default): 1x (720p/1080p)
280# 3: 2x (1440p/2160p)
281# 4: 3x (2160p/3240p)
282# 5: 4x (2880p/4320p)
283# 6: 5x (3600p/5400p)
284# 7: 6x (4320p/6480p)
285resolution_setup =
286
287# Pixel filter to use when up- or down-sampling rendered frames.
288# 0: Nearest Neighbor
289# 1 (default): Bilinear
290# 2: Bicubic
291# 3: Gaussian
292# 4: ScaleForce
293# 5: AMD FidelityFX™️ Super Resolution [Vulkan Only]
294scaling_filter =
295
296# Anti-Aliasing (AA)
297# 0 (default): None, 1: FXAA
298anti_aliasing =
299
300# Whether to use fullscreen or borderless window mode
301# 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen
302fullscreen_mode =
303
304# Aspect ratio
305# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window
306aspect_ratio =
307
308# Anisotropic filtering
309# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x
310max_anisotropy =
311
312# Whether to enable VSync or not.
313# OpenGL: Values other than 0 enable VSync
314# Vulkan: FIFO is selected if the requested mode is not supported by the driver.
315# FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate.
316# FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down.
317# Mailbox can have lower latency than FIFO and does not tear but may drop frames.
318# Immediate (no synchronization) just presents whatever is available and can exhibit tearing.
319# 0: Immediate (Off), 1 (Default): Mailbox (On), 2: FIFO, 3: FIFO Relaxed
320use_vsync =
321
322# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is
323# not available and GLASM is selected, GLSL will be used.
324# 0: GLSL, 1 (default): GLASM, 2: SPIR-V
325shader_backend =
326
327# Whether to allow asynchronous shader building.
328# 0 (default): Off, 1: On
329use_asynchronous_shaders =
330
331# Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory.
332# 0 (default): Off, 1: On
333use_reactive_flushing =
334
335# NVDEC emulation.
336# 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding
337nvdec_emulation =
338
339# Accelerate ASTC texture decoding.
340# 0 (default): Off, 1: On
341accelerate_astc =
342
343# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value
344# 0: Off, 1: On (default)
345use_speed_limit =
346
347# Limits the speed of the game to run no faster than this value as a percentage of target speed
348# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default)
349speed_limit =
350
351# Whether to use disk based shader cache
352# 0: Off, 1 (default): On
353use_disk_shader_cache =
354
355# Which gpu accuracy level to use
356# 0 (default): Normal, 1: High, 2: Extreme (Very slow)
357gpu_accuracy =
358
359# Whether to use asynchronous GPU emulation
360# 0 : Off (slow), 1 (default): On (fast)
361use_asynchronous_gpu_emulation =
362
363# Inform the guest that GPU operations completed more quickly than they did.
364# 0: Off, 1 (default): On
365use_fast_gpu_time =
366
367# Force unmodified buffers to be flushed, which can cost performance.
368# 0: Off (default), 1: On
369use_pessimistic_flushes =
370
371# Whether to use garbage collection or not for GPU caches.
372# 0 (default): Off, 1: On
373use_caches_gc =
374
375# The clear color for the renderer. What shows up on the sides of the bottom screen.
376# Must be in range of 0-255. Defaults to 0 for all.
377bg_red =
378bg_blue =
379bg_green =
380
381[Audio]
382# Which audio output engine to use.
383# auto (default): Auto-select
384# cubeb: Cubeb audio engine (if available)
385# sdl2: SDL2 audio engine (if available)
386# null: No audio output
387output_engine =
388
389# Which audio device to use.
390# auto (default): Auto-select
391output_device =
392
393# Output volume.
394# 100 (default): 100%, 0; mute
395volume =
396
397[Data Storage]
398# Whether to create a virtual SD card.
399# 1: Yes, 0 (default): No
400use_virtual_sd =
401
402# Whether or not to enable gamecard emulation
403# 1: Yes, 0 (default): No
404gamecard_inserted =
405
406# Whether or not the gamecard should be emulated as the current game
407# If 'gamecard_inserted' is 0 this setting is irrelevant
408# 1: Yes, 0 (default): No
409gamecard_current_game =
410
411# Path to an XCI file to use as the gamecard
412# If 'gamecard_inserted' is 0 this setting is irrelevant
413# If 'gamecard_current_game' is 1 this setting is irrelevant
414gamecard_path =
415
416[System]
417# Whether the system is docked
418# 1 (default): Yes, 0: No
419use_docked_mode =
420
421# Sets the seed for the RNG generator built into the switch
422# rng_seed will be ignored and randomly generated if rng_seed_enabled is false
423rng_seed_enabled =
424rng_seed =
425
426# Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service
427# This will auto-increment, with the time set being the time the game is started
428# This override will only occur if custom_rtc_enabled is true, otherwise the current time is used
429custom_rtc_enabled =
430custom_rtc =
431
432# Sets the systems language index
433# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
434# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French,
435# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese
436language_index =
437
438# The system region that yuzu will use during emulation
439# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
440region_index =
441
442# The system time zone that yuzu will use during emulation
443# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone
444time_zone_index =
445
446# Sets the sound output mode.
447# 0: Mono, 1 (default): Stereo, 2: Surround
448sound_index =
449
450[Miscellaneous]
451# A filter which removes logs below a certain logging level.
452# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical
453log_filter = *:Trace
454
455# Use developer keys
456# 0 (default): Disabled, 1: Enabled
457use_dev_keys =
458
459[Debugging]
460# Record frame time data, can be found in the log directory. Boolean value
461record_frame_times =
462# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
463dump_exefs=false
464# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them
465dump_nso=false
466# Determines whether or not yuzu will save the filesystem access log.
467enable_fs_access_log=false
468# Enables verbose reporting services
469reporting_services =
470# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
471# false: Retail/Normal Mode (default), true: Kiosk Mode
472quest_flag =
473# Determines whether debug asserts should be enabled, which will throw an exception on asserts.
474# false: Disabled (default), true: Enabled
475use_debug_asserts =
476# Determines whether unimplemented HLE service calls should be automatically stubbed.
477# false: Disabled (default), true: Enabled
478use_auto_stub =
479# Enables/Disables the macro JIT compiler
480disable_macro_jit=false
481# Determines whether to enable the GDB stub and wait for the debugger to attach before running.
482# false: Disabled (default), true: Enabled
483use_gdbstub=false
484# The port to use for the GDB server, if it is enabled.
485gdbstub_port=6543
486
487[WebService]
488# Whether or not to enable telemetry
489# 0: No, 1 (default): Yes
490enable_telemetry =
491# URL for Web API
492web_api_url = https://api.yuzu-emu.org
493# Username and token for yuzu Web Service
494# See https://profile.yuzu-emu.org/ for more info
495yuzu_username =
496yuzu_token =
497
498[Network]
499# Name of the network interface device to use with yuzu LAN play.
500# e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo'
501# e.g. On Windows: 'Ethernet', 'Wi-Fi'
502network_interface =
503
504[AddOns]
505# Used to disable add-ons
506# List of title IDs of games that will have add-ons disabled (separated by '|'):
507title_ids =
508# 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 '|')
509# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey
510)";
511} // 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 @@
52#include "core/hle/service/am/applets/applets.h" 52#include "core/hle/service/am/applets/applets.h"
53#include "core/hle/service/filesystem/filesystem.h" 53#include "core/hle/service/filesystem/filesystem.h"
54#include "core/loader/loader.h" 54#include "core/loader/loader.h"
55#include "frontend_common/config.h"
55#include "jni/android_common/android_common.h" 56#include "jni/android_common/android_common.h"
56#include "jni/config.h"
57#include "jni/id_cache.h" 57#include "jni/id_cache.h"
58#include "jni/native.h" 58#include "jni/native.h"
59#include "video_core/renderer_base.h" 59#include "video_core/renderer_base.h"
@@ -664,8 +664,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased(JNIEnv* env, jclass c
664 664
665void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz, 665void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeSystem(JNIEnv* env, jclass clazz,
666 jboolean reload) { 666 jboolean reload) {
667 // Create the default config.ini.
668 Config{};
669 // Initialize the emulated system. 667 // Initialize the emulated system.
670 if (!reload) { 668 if (!reload) {
671 EmulationSession::GetInstance().System().Initialize(); 669 EmulationSession::GetInstance().System().Initialize();
@@ -680,17 +678,6 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore(JNIEnv* env, jclass cl
680void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z( 678void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
681 JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {} 679 JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate) {}
682 680
683void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass clazz) {
684 Config{};
685}
686
687void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz,
688 jstring j_game_id) {
689 std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
690
691 env->ReleaseStringUTFChars(j_game_id, game_id.data());
692}
693
694jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) { 681jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jclass clazz) {
695 jdoubleArray j_stats = env->NewDoubleArray(4); 682 jdoubleArray j_stats = env->NewDoubleArray(4);
696 683
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 @@
5 5
6#include <jni.h> 6#include <jni.h>
7 7
8#include "android_config.h"
9#include "android_settings.h"
8#include "common/logging/log.h" 10#include "common/logging/log.h"
9#include "common/settings.h" 11#include "common/settings.h"
12#include "frontend_common/config.h"
10#include "jni/android_common/android_common.h" 13#include "jni/android_common/android_common.h"
11#include "jni/config.h" 14
12#include "uisettings.h" 15std::unique_ptr<AndroidConfig> config;
13 16
14template <typename T> 17template <typename T>
15Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { 18Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
@@ -28,6 +31,22 @@ Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
28 31
29extern "C" { 32extern "C" {
30 33
34void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeConfig(JNIEnv* env, jobject obj) {
35 config = std::make_unique<AndroidConfig>();
36}
37
38void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadConfig(JNIEnv* env, jobject obj) {
39 config.reset();
40}
41
42void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadSettings(JNIEnv* env, jobject obj) {
43 config->AndroidConfig::ReloadAllValues();
44}
45
46void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveSettings(JNIEnv* env, jobject obj) {
47 config->AndroidConfig::SaveAllValues();
48}
49
31jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj, 50jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj,
32 jstring jkey, jboolean getDefault) { 51 jstring jkey, jboolean getDefault) {
33 auto setting = getSetting<bool>(env, jkey); 52 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) {
206 case Category::UiAudio: 206 case Category::UiAudio:
207 return "UiAudio"; 207 return "UiAudio";
208 case Category::UiLayout: 208 case Category::UiLayout:
209 return "UiLayout"; 209 return "UILayout";
210 case Category::UiGameList: 210 case Category::UiGameList:
211 return "UiGameList"; 211 return "UIGameList";
212 case Category::Screenshots: 212 case Category::Screenshots:
213 return "Screenshots"; 213 return "Screenshots";
214 case Category::Shortcuts: 214 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 {
232 SwitchableSetting<bool> use_asynchronous_gpu_emulation{ 232 SwitchableSetting<bool> use_asynchronous_gpu_emulation{
233 linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer}; 233 linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer};
234 SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage, 234 SwitchableSetting<AstcDecodeMode, true> accelerate_astc{linkage,
235#ifdef ANDROID
236 AstcDecodeMode::Cpu,
237#else
235 AstcDecodeMode::Gpu, 238 AstcDecodeMode::Gpu,
239#endif
236 AstcDecodeMode::Cpu, 240 AstcDecodeMode::Cpu,
237 AstcDecodeMode::CpuAsynchronous, 241 AstcDecodeMode::CpuAsynchronous,
238 "accelerate_astc", 242 "accelerate_astc",
@@ -304,7 +308,11 @@ struct Values {
304 linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true}; 308 linkage, 0, "bg_blue", Category::Renderer, Specialization::Default, true, true};
305 309
306 SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage, 310 SwitchableSetting<GpuAccuracy, true> gpu_accuracy{linkage,
311#ifdef ANDROID
312 GpuAccuracy::Normal,
313#else
307 GpuAccuracy::High, 314 GpuAccuracy::High,
315#endif
308 GpuAccuracy::Normal, 316 GpuAccuracy::Normal,
309 GpuAccuracy::Extreme, 317 GpuAccuracy::Extreme,
310 "gpu_accuracy", 318 "gpu_accuracy",
@@ -313,20 +321,38 @@ struct Values {
313 true, 321 true,
314 true}; 322 true};
315 GpuAccuracy current_gpu_accuracy{GpuAccuracy::High}; 323 GpuAccuracy current_gpu_accuracy{GpuAccuracy::High};
316 SwitchableSetting<AnisotropyMode, true> max_anisotropy{ 324 SwitchableSetting<AnisotropyMode, true> max_anisotropy{linkage,
317 linkage, AnisotropyMode::Automatic, AnisotropyMode::Automatic, AnisotropyMode::X16, 325#ifdef ANDROID
318 "max_anisotropy", Category::RendererAdvanced}; 326 AnisotropyMode::Default,
327#else
328 AnisotropyMode::Automatic,
329#endif
330 AnisotropyMode::Automatic,
331 AnisotropyMode::X16,
332 "max_anisotropy",
333 Category::RendererAdvanced};
319 SwitchableSetting<AstcRecompression, true> astc_recompression{linkage, 334 SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
320 AstcRecompression::Uncompressed, 335 AstcRecompression::Uncompressed,
321 AstcRecompression::Uncompressed, 336 AstcRecompression::Uncompressed,
322 AstcRecompression::Bc3, 337 AstcRecompression::Bc3,
323 "astc_recompression", 338 "astc_recompression",
324 Category::RendererAdvanced}; 339 Category::RendererAdvanced};
325 SwitchableSetting<bool> async_presentation{linkage, false, "async_presentation", 340 SwitchableSetting<bool> async_presentation{linkage,
326 Category::RendererAdvanced}; 341#ifdef ANDROID
342 true,
343#else
344 false,
345#endif
346 "async_presentation", Category::RendererAdvanced};
327 SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock", 347 SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
328 Category::RendererAdvanced}; 348 Category::RendererAdvanced};
329 SwitchableSetting<bool> use_reactive_flushing{linkage, true, "use_reactive_flushing", 349 SwitchableSetting<bool> use_reactive_flushing{linkage,
350#ifdef ANDROID
351 false,
352#else
353 true,
354#endif
355 "use_reactive_flushing",
330 Category::RendererAdvanced}; 356 Category::RendererAdvanced};
331 SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", 357 SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
332 Category::RendererAdvanced}; 358 Category::RendererAdvanced};
@@ -390,7 +416,11 @@ struct Values {
390 Setting<s32> current_user{linkage, 0, "current_user", Category::System}; 416 Setting<s32> current_user{linkage, 0, "current_user", Category::System};
391 417
392 SwitchableSetting<ConsoleMode> use_docked_mode{linkage, 418 SwitchableSetting<ConsoleMode> use_docked_mode{linkage,
419#ifdef ANDROID
420 ConsoleMode::Handheld,
421#else
393 ConsoleMode::Docked, 422 ConsoleMode::Docked,
423#endif
394 "use_docked_mode", 424 "use_docked_mode",
395 Category::System, 425 Category::System,
396 Specialization::Radio, 426 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
529 hle/service/hid/hid_server.h 529 hle/service/hid/hid_server.h
530 hle/service/hid/hid_system_server.cpp 530 hle/service/hid/hid_system_server.cpp
531 hle/service/hid/hid_system_server.h 531 hle/service/hid/hid_system_server.h
532 hle/service/hid/hid_util.h
532 hle/service/hid/hidbus.cpp 533 hle/service/hid/hidbus.cpp
533 hle/service/hid/hidbus.h 534 hle/service/hid/hidbus.h
534 hle/service/hid/irs.cpp 535 hle/service/hid/irs.cpp
@@ -540,8 +541,8 @@ add_library(core STATIC
540 hle/service/hid/xcd.cpp 541 hle/service/hid/xcd.cpp
541 hle/service/hid/xcd.h 542 hle/service/hid/xcd.h
542 hle/service/hid/errors.h 543 hle/service/hid/errors.h
543 hle/service/hid/controllers/console_sixaxis.cpp 544 hle/service/hid/controllers/console_six_axis.cpp
544 hle/service/hid/controllers/console_sixaxis.h 545 hle/service/hid/controllers/console_six_axis.h
545 hle/service/hid/controllers/controller_base.cpp 546 hle/service/hid/controllers/controller_base.cpp
546 hle/service/hid/controllers/controller_base.h 547 hle/service/hid/controllers/controller_base.h
547 hle/service/hid/controllers/debug_pad.cpp 548 hle/service/hid/controllers/debug_pad.cpp
@@ -556,6 +557,10 @@ add_library(core STATIC
556 hle/service/hid/controllers/npad.h 557 hle/service/hid/controllers/npad.h
557 hle/service/hid/controllers/palma.cpp 558 hle/service/hid/controllers/palma.cpp
558 hle/service/hid/controllers/palma.h 559 hle/service/hid/controllers/palma.h
560 hle/service/hid/controllers/seven_six_axis.cpp
561 hle/service/hid/controllers/seven_six_axis.h
562 hle/service/hid/controllers/six_axis.cpp
563 hle/service/hid/controllers/six_axis.h
559 hle/service/hid/controllers/stubbed.cpp 564 hle/service/hid/controllers/stubbed.cpp
560 hle/service/hid/controllers/stubbed.h 565 hle/service/hid/controllers/stubbed.h
561 hle/service/hid/controllers/touchscreen.cpp 566 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 @@
8#include "common/thread.h" 8#include "common/thread.h"
9#include "core/hid/emulated_controller.h" 9#include "core/hid/emulated_controller.h"
10#include "core/hid/input_converter.h" 10#include "core/hid/input_converter.h"
11#include "core/hle/service/hid/hid_util.h"
11 12
12namespace Core::HID { 13namespace Core::HID {
13constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 14constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
@@ -82,7 +83,7 @@ Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleInde
82} 83}
83 84
84void EmulatedController::ReloadFromSettings() { 85void EmulatedController::ReloadFromSettings() {
85 const auto player_index = NpadIdTypeToIndex(npad_id_type); 86 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
86 const auto& player = Settings::values.players.GetValue()[player_index]; 87 const auto& player = Settings::values.players.GetValue()[player_index];
87 88
88 for (std::size_t index = 0; index < player.buttons.size(); ++index) { 89 for (std::size_t index = 0; index < player.buttons.size(); ++index) {
@@ -118,7 +119,7 @@ void EmulatedController::ReloadFromSettings() {
118} 119}
119 120
120void EmulatedController::ReloadColorsFromSettings() { 121void EmulatedController::ReloadColorsFromSettings() {
121 const auto player_index = NpadIdTypeToIndex(npad_id_type); 122 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
122 const auto& player = Settings::values.players.GetValue()[player_index]; 123 const auto& player = Settings::values.players.GetValue()[player_index];
123 124
124 // Avoid updating colors if overridden by physical controller 125 // Avoid updating colors if overridden by physical controller
@@ -215,7 +216,7 @@ void EmulatedController::LoadDevices() {
215} 216}
216 217
217void EmulatedController::LoadTASParams() { 218void EmulatedController::LoadTASParams() {
218 const auto player_index = NpadIdTypeToIndex(npad_id_type); 219 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
219 Common::ParamPackage common_params{}; 220 Common::ParamPackage common_params{};
220 common_params.Set("engine", "tas"); 221 common_params.Set("engine", "tas");
221 common_params.Set("port", static_cast<int>(player_index)); 222 common_params.Set("port", static_cast<int>(player_index));
@@ -264,7 +265,7 @@ void EmulatedController::LoadTASParams() {
264} 265}
265 266
266void EmulatedController::LoadVirtualGamepadParams() { 267void EmulatedController::LoadVirtualGamepadParams() {
267 const auto player_index = NpadIdTypeToIndex(npad_id_type); 268 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
268 Common::ParamPackage common_params{}; 269 Common::ParamPackage common_params{};
269 common_params.Set("engine", "virtual_gamepad"); 270 common_params.Set("engine", "virtual_gamepad");
270 common_params.Set("port", static_cast<int>(player_index)); 271 common_params.Set("port", static_cast<int>(player_index));
@@ -615,7 +616,7 @@ bool EmulatedController::IsConfiguring() const {
615} 616}
616 617
617void EmulatedController::SaveCurrentConfig() { 618void EmulatedController::SaveCurrentConfig() {
618 const auto player_index = NpadIdTypeToIndex(npad_id_type); 619 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
619 auto& player = Settings::values.players.GetValue()[player_index]; 620 auto& player = Settings::values.players.GetValue()[player_index];
620 player.connected = is_connected; 621 player.connected = is_connected;
621 player.controller_type = MapNPadToSettingsType(npad_type); 622 player.controller_type = MapNPadToSettingsType(npad_type);
@@ -1212,7 +1213,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
1212 if (!output_devices[device_index]) { 1213 if (!output_devices[device_index]) {
1213 return false; 1214 return false;
1214 } 1215 }
1215 const auto player_index = NpadIdTypeToIndex(npad_id_type); 1216 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
1216 const auto& player = Settings::values.players.GetValue()[player_index]; 1217 const auto& player = Settings::values.players.GetValue()[player_index];
1217 const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f; 1218 const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f;
1218 1219
@@ -1238,7 +1239,7 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
1238} 1239}
1239 1240
1240bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { 1241bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {
1241 const auto player_index = NpadIdTypeToIndex(npad_id_type); 1242 const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
1242 const auto& player = Settings::values.players.GetValue()[player_index]; 1243 const auto& player = Settings::values.players.GetValue()[player_index];
1243 1244
1244 if (!player.vibration_enabled) { 1245 if (!player.vibration_enabled) {
@@ -1648,7 +1649,7 @@ void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
1648 } 1649 }
1649 if (is_connected) { 1650 if (is_connected) {
1650 LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", 1651 LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
1651 NpadIdTypeToIndex(npad_id_type)); 1652 Service::HID::NpadIdTypeToIndex(npad_id_type));
1652 } 1653 }
1653 npad_type = npad_type_; 1654 npad_type = npad_type_;
1654} 1655}
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 @@
6#include "core/hid/emulated_controller.h" 6#include "core/hid/emulated_controller.h"
7#include "core/hid/emulated_devices.h" 7#include "core/hid/emulated_devices.h"
8#include "core/hid/hid_core.h" 8#include "core/hid/hid_core.h"
9#include "core/hle/service/hid/hid_util.h"
9 10
10namespace Core::HID { 11namespace Core::HID {
11 12
@@ -98,11 +99,11 @@ const EmulatedDevices* HIDCore::GetEmulatedDevices() const {
98} 99}
99 100
100EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) { 101EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) {
101 return GetEmulatedController(IndexToNpadIdType(index)); 102 return GetEmulatedController(Service::HID::IndexToNpadIdType(index));
102} 103}
103 104
104const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) const { 105const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t index) const {
105 return GetEmulatedController(IndexToNpadIdType(index)); 106 return GetEmulatedController(Service::HID::IndexToNpadIdType(index));
106} 107}
107 108
108void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) { 109void 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 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/point.h" 9#include "common/point.h"
10#include "common/uuid.h" 10#include "common/uuid.h"
11#include "common/vector_math.h"
11 12
12namespace Core::HID { 13namespace Core::HID {
13 14
@@ -598,6 +599,29 @@ struct SixAxisSensorIcInformation {
598static_assert(sizeof(SixAxisSensorIcInformation) == 0xC8, 599static_assert(sizeof(SixAxisSensorIcInformation) == 0xC8,
599 "SixAxisSensorIcInformation is an invalid size"); 600 "SixAxisSensorIcInformation is an invalid size");
600 601
602// This is nn::hid::SixAxisSensorAttribute
603struct SixAxisSensorAttribute {
604 union {
605 u32 raw{};
606 BitField<0, 1, u32> is_connected;
607 BitField<1, 1, u32> is_interpolated;
608 };
609};
610static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
611
612// This is nn::hid::SixAxisSensorState
613struct SixAxisSensorState {
614 s64 delta_time{};
615 s64 sampling_number{};
616 Common::Vec3f accel{};
617 Common::Vec3f gyro{};
618 Common::Vec3f rotation{};
619 std::array<Common::Vec3f, 3> orientation{};
620 SixAxisSensorAttribute attribute{};
621 INSERT_PADDING_BYTES(4); // Reserved
622};
623static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
624
601// This is nn::hid::VibrationDeviceHandle 625// This is nn::hid::VibrationDeviceHandle
602struct VibrationDeviceHandle { 626struct VibrationDeviceHandle {
603 NpadStyleIndex npad_type{NpadStyleIndex::None}; 627 NpadStyleIndex npad_type{NpadStyleIndex::None};
@@ -708,60 +732,4 @@ struct UniquePadId {
708}; 732};
709static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size"); 733static_assert(sizeof(UniquePadId) == 0x8, "UniquePadId is an invalid size");
710 734
711/// Converts a NpadIdType to an array index.
712constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) {
713 switch (npad_id_type) {
714 case NpadIdType::Player1:
715 return 0;
716 case NpadIdType::Player2:
717 return 1;
718 case NpadIdType::Player3:
719 return 2;
720 case NpadIdType::Player4:
721 return 3;
722 case NpadIdType::Player5:
723 return 4;
724 case NpadIdType::Player6:
725 return 5;
726 case NpadIdType::Player7:
727 return 6;
728 case NpadIdType::Player8:
729 return 7;
730 case NpadIdType::Handheld:
731 return 8;
732 case NpadIdType::Other:
733 return 9;
734 default:
735 return 0;
736 }
737}
738
739/// Converts an array index to a NpadIdType
740constexpr NpadIdType IndexToNpadIdType(size_t index) {
741 switch (index) {
742 case 0:
743 return NpadIdType::Player1;
744 case 1:
745 return NpadIdType::Player2;
746 case 2:
747 return NpadIdType::Player3;
748 case 3:
749 return NpadIdType::Player4;
750 case 4:
751 return NpadIdType::Player5;
752 case 5:
753 return NpadIdType::Player6;
754 case 6:
755 return NpadIdType::Player7;
756 case 7:
757 return NpadIdType::Player8;
758 case 8:
759 return NpadIdType::Handheld;
760 case 9:
761 return NpadIdType::Other;
762 default:
763 return NpadIdType::Invalid;
764 }
765}
766
767} // namespace Core::HID 735} // 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)
13 : npad{system.ServiceManager() 13 : npad{system.ServiceManager()
14 .GetService<Service::HID::IHidServer>("hid") 14 .GetService<Service::HID::IHidServer>("hid")
15 ->GetResourceManager() 15 ->GetResourceManager()
16 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} { 16 ->GetNpad()} {
17 ResetButtonStates(); 17 ResetButtonStates();
18} 18}
19 19
20InputInterpreter::~InputInterpreter() = default; 20InputInterpreter::~InputInterpreter() = default;
21 21
22void InputInterpreter::PollInput() { 22void InputInterpreter::PollInput() {
23 const auto button_state = npad.GetAndResetPressState(); 23 const auto button_state = npad->GetAndResetPressState();
24 24
25 previous_index = current_index; 25 previous_index = current_index;
26 current_index = (current_index + 1) % button_states.size(); 26 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;
16} 16}
17 17
18namespace Service::HID { 18namespace Service::HID {
19class Controller_NPad; 19class NPad;
20} 20}
21 21
22/** 22/**
@@ -101,7 +101,7 @@ public:
101 } 101 }
102 102
103private: 103private:
104 Service::HID::Controller_NPad& npad; 104 std::shared_ptr<Service::HID::NPad> npad;
105 105
106 /// Stores 9 consecutive button states polled from HID. 106 /// Stores 9 consecutive button states polled from HID.
107 std::array<Core::HID::NpadButton, 9> button_states{}; 107 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:
32 {10200, nullptr, "SendFriendRequestForApplication"}, 32 {10200, nullptr, "SendFriendRequestForApplication"},
33 {10211, nullptr, "AddFacedFriendRequestForApplication"}, 33 {10211, nullptr, "AddFacedFriendRequestForApplication"},
34 {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"}, 34 {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"},
35 {10420, nullptr, "IsBlockedUserListCacheAvailable"}, 35 {10420, &IFriendService::CheckBlockedUserListAvailability, "CheckBlockedUserListAvailability"},
36 {10421, nullptr, "EnsureBlockedUserListAvailable"}, 36 {10421, nullptr, "EnsureBlockedUserListAvailable"},
37 {10500, nullptr, "GetProfileList"}, 37 {10500, nullptr, "GetProfileList"},
38 {10600, nullptr, "DeclareOpenOnlinePlaySession"}, 38 {10600, nullptr, "DeclareOpenOnlinePlaySession"},
@@ -206,6 +206,17 @@ private:
206 rb.Push(true); 206 rb.Push(true);
207 } 207 }
208 208
209 void CheckBlockedUserListAvailability(HLERequestContext& ctx) {
210 IPC::RequestParser rp{ctx};
211 const auto uuid{rp.PopRaw<Common::UUID>()};
212
213 LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString());
214
215 IPC::ResponseBuilder rb{ctx, 3};
216 rb.Push(ResultSuccess);
217 rb.Push(true);
218 }
219
209 KernelHelpers::ServiceContext service_context; 220 KernelHelpers::ServiceContext service_context;
210 221
211 Kernel::KEvent* completion_event; 222 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 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/core_timing.h"
6#include "core/hid/emulated_console.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/console_six_axis.h"
9#include "core/memory.h"
10
11namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
13
14ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
15 : ControllerBase{hid_core_} {
16 console = hid_core.GetEmulatedConsole();
17 static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
18 "ConsoleSharedMemory is bigger than the shared memory");
19 shared_memory = std::construct_at(
20 reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
21}
22
23ConsoleSixAxis::~ConsoleSixAxis() = default;
24
25void ConsoleSixAxis::OnInit() {}
26
27void ConsoleSixAxis::OnRelease() {}
28
29void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
30 if (!IsControllerActivated()) {
31 return;
32 }
33
34 const auto motion_status = console->GetMotion();
35
36 shared_memory->sampling_number++;
37 shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
38 shared_memory->verticalization_error = motion_status.verticalization_error;
39 shared_memory->gyro_bias = motion_status.gyro_bias;
40}
41
42} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/vector_math.h"
7#include "core/hle/service/hid/controllers/controller_base.h"
8
9namespace Core::HID {
10class EmulatedConsole;
11} // namespace Core::HID
12
13namespace Service::HID {
14class ConsoleSixAxis final : public ControllerBase {
15public:
16 explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
17 ~ConsoleSixAxis() override;
18
19 // Called when the controller is initialized
20 void OnInit() override;
21
22 // When the controller is released
23 void OnRelease() override;
24
25 // When the controller is requesting an update for the shared memory
26 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
27
28private:
29 // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
30 struct ConsoleSharedMemory {
31 u64 sampling_number{};
32 bool is_seven_six_axis_sensor_at_rest{};
33 INSERT_PADDING_BYTES(3); // padding
34 f32 verticalization_error{};
35 Common::Vec3f gyro_bias{};
36 INSERT_PADDING_BYTES(4); // padding
37 };
38 static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
39
40 ConsoleSharedMemory* shared_memory = nullptr;
41 Core::HID::EmulatedConsole* console = nullptr;
42};
43} // 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 @@
13namespace Service::HID { 13namespace Service::HID {
14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; 14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000;
15 15
16Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 16DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
17 : ControllerBase{hid_core_} { 17 : ControllerBase{hid_core_} {
18 static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size, 18 static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
19 "DebugPadSharedMemory is bigger than the shared memory"); 19 "DebugPadSharedMemory is bigger than the shared memory");
@@ -22,13 +22,13 @@ Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_
22 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); 22 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
23} 23}
24 24
25Controller_DebugPad::~Controller_DebugPad() = default; 25DebugPad::~DebugPad() = default;
26 26
27void Controller_DebugPad::OnInit() {} 27void DebugPad::OnInit() {}
28 28
29void Controller_DebugPad::OnRelease() {} 29void DebugPad::OnRelease() {}
30 30
31void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 31void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
32 if (!IsControllerActivated()) { 32 if (!IsControllerActivated()) {
33 shared_memory->debug_pad_lifo.buffer_count = 0; 33 shared_memory->debug_pad_lifo.buffer_count = 0;
34 shared_memory->debug_pad_lifo.buffer_tail = 0; 34 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;
15} // namespace Core::HID 15} // namespace Core::HID
16 16
17namespace Service::HID { 17namespace Service::HID {
18class Controller_DebugPad final : public ControllerBase { 18class DebugPad final : public ControllerBase {
19public: 19public:
20 explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 20 explicit DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
21 ~Controller_DebugPad() override; 21 ~DebugPad() override;
22 22
23 // Called when the controller is initialized 23 // Called when the controller is initialized
24 void OnInit() override; 24 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) {
23 return static_cast<f32>(num * num); 23 return static_cast<f32>(num * num);
24} 24}
25 25
26Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 26Gesture::Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
27 : ControllerBase(hid_core_) { 27 : ControllerBase(hid_core_) {
28 static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size, 28 static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size,
29 "GestureSharedMemory is bigger than the shared memory"); 29 "GestureSharedMemory is bigger than the shared memory");
@@ -31,17 +31,17 @@ Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_sh
31 reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); 31 reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
32 console = hid_core.GetEmulatedConsole(); 32 console = hid_core.GetEmulatedConsole();
33} 33}
34Controller_Gesture::~Controller_Gesture() = default; 34Gesture::~Gesture() = default;
35 35
36void Controller_Gesture::OnInit() { 36void Gesture::OnInit() {
37 shared_memory->gesture_lifo.buffer_count = 0; 37 shared_memory->gesture_lifo.buffer_count = 0;
38 shared_memory->gesture_lifo.buffer_tail = 0; 38 shared_memory->gesture_lifo.buffer_tail = 0;
39 force_update = true; 39 force_update = true;
40} 40}
41 41
42void Controller_Gesture::OnRelease() {} 42void Gesture::OnRelease() {}
43 43
44void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 44void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
45 if (!IsControllerActivated()) { 45 if (!IsControllerActivated()) {
46 shared_memory->gesture_lifo.buffer_count = 0; 46 shared_memory->gesture_lifo.buffer_count = 0;
47 shared_memory->gesture_lifo.buffer_tail = 0; 47 shared_memory->gesture_lifo.buffer_tail = 0;
@@ -64,7 +64,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
64 UpdateGestureSharedMemory(gesture, time_difference); 64 UpdateGestureSharedMemory(gesture, time_difference);
65} 65}
66 66
67void Controller_Gesture::ReadTouchInput() { 67void Gesture::ReadTouchInput() {
68 if (!Settings::values.touchscreen.enabled) { 68 if (!Settings::values.touchscreen.enabled) {
69 fingers = {}; 69 fingers = {};
70 return; 70 return;
@@ -76,8 +76,7 @@ void Controller_Gesture::ReadTouchInput() {
76 } 76 }
77} 77}
78 78
79bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, 79bool Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) {
80 f32 time_difference) {
81 const auto& last_entry = GetLastGestureEntry(); 80 const auto& last_entry = GetLastGestureEntry();
82 if (force_update) { 81 if (force_update) {
83 force_update = false; 82 force_update = false;
@@ -100,8 +99,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
100 return false; 99 return false;
101} 100}
102 101
103void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, 102void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference) {
104 f32 time_difference) {
105 GestureType type = GestureType::Idle; 103 GestureType type = GestureType::Idle;
106 GestureAttribute attributes{}; 104 GestureAttribute attributes{};
107 105
@@ -138,8 +136,8 @@ void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture,
138 shared_memory->gesture_lifo.WriteNextEntry(next_state); 136 shared_memory->gesture_lifo.WriteNextEntry(next_state);
139} 137}
140 138
141void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, 139void Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
142 GestureAttribute& attributes) { 140 GestureAttribute& attributes) {
143 const auto& last_entry = GetLastGestureEntry(); 141 const auto& last_entry = GetLastGestureEntry();
144 142
145 gesture.detection_count++; 143 gesture.detection_count++;
@@ -152,8 +150,8 @@ void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& typ
152 } 150 }
153} 151}
154 152
155void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, 153void Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type,
156 f32 time_difference) { 154 f32 time_difference) {
157 const auto& last_entry = GetLastGestureEntry(); 155 const auto& last_entry = GetLastGestureEntry();
158 156
159 // Promote to pan type if touch moved 157 // Promote to pan type if touch moved
@@ -186,9 +184,8 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Gestu
186 } 184 }
187} 185}
188 186
189void Controller_Gesture::EndGesture(GestureProperties& gesture, 187void Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
190 GestureProperties& last_gesture_props, GestureType& type, 188 GestureType& type, GestureAttribute& attributes, f32 time_difference) {
191 GestureAttribute& attributes, f32 time_difference) {
192 const auto& last_entry = GetLastGestureEntry(); 189 const auto& last_entry = GetLastGestureEntry();
193 190
194 if (last_gesture_props.active_points != 0) { 191 if (last_gesture_props.active_points != 0) {
@@ -222,9 +219,8 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture,
222 } 219 }
223} 220}
224 221
225void Controller_Gesture::SetTapEvent(GestureProperties& gesture, 222void Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
226 GestureProperties& last_gesture_props, GestureType& type, 223 GestureType& type, GestureAttribute& attributes) {
227 GestureAttribute& attributes) {
228 type = GestureType::Tap; 224 type = GestureType::Tap;
229 gesture = last_gesture_props; 225 gesture = last_gesture_props;
230 force_update = true; 226 force_update = true;
@@ -236,9 +232,8 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
236 } 232 }
237} 233}
238 234
239void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, 235void Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
240 GestureProperties& last_gesture_props, GestureType& type, 236 GestureType& type, f32 time_difference) {
241 f32 time_difference) {
242 const auto& last_entry = GetLastGestureEntry(); 237 const auto& last_entry = GetLastGestureEntry();
243 238
244 next_state.delta = gesture.mid_point - last_entry.pos; 239 next_state.delta = gesture.mid_point - last_entry.pos;
@@ -263,9 +258,8 @@ void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture,
263 } 258 }
264} 259}
265 260
266void Controller_Gesture::EndPanEvent(GestureProperties& gesture, 261void Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
267 GestureProperties& last_gesture_props, GestureType& type, 262 GestureType& type, f32 time_difference) {
268 f32 time_difference) {
269 const auto& last_entry = GetLastGestureEntry(); 263 const auto& last_entry = GetLastGestureEntry();
270 next_state.vel_x = 264 next_state.vel_x =
271 static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); 265 static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference);
@@ -287,8 +281,8 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
287 force_update = true; 281 force_update = true;
288} 282}
289 283
290void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, 284void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
291 GestureProperties& last_gesture_props, GestureType& type) { 285 GestureType& type) {
292 const auto& last_entry = GetLastGestureEntry(); 286 const auto& last_entry = GetLastGestureEntry();
293 287
294 type = GestureType::Swipe; 288 type = GestureType::Swipe;
@@ -311,11 +305,11 @@ void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture,
311 next_state.direction = GestureDirection::Up; 305 next_state.direction = GestureDirection::Up;
312} 306}
313 307
314const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { 308const Gesture::GestureState& Gesture::GetLastGestureEntry() const {
315 return shared_memory->gesture_lifo.ReadCurrentEntry().state; 309 return shared_memory->gesture_lifo.ReadCurrentEntry().state;
316} 310}
317 311
318Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { 312Gesture::GestureProperties Gesture::GetGestureProperties() {
319 GestureProperties gesture; 313 GestureProperties gesture;
320 std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; 314 std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
321 const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), 315 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 @@
12#include "core/hle/service/hid/ring_lifo.h" 12#include "core/hle/service/hid/ring_lifo.h"
13 13
14namespace Service::HID { 14namespace Service::HID {
15class Controller_Gesture final : public ControllerBase { 15class Gesture final : public ControllerBase {
16public: 16public:
17 explicit Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 17 explicit Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
18 ~Controller_Gesture() override; 18 ~Gesture() override;
19 19
20 // Called when the controller is initialized 20 // Called when the controller is initialized
21 void OnInit() override; 21 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 @@
12namespace Service::HID { 12namespace Service::HID {
13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
14 14
15Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 15Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
16 : ControllerBase{hid_core_} { 16 : ControllerBase{hid_core_} {
17 static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size, 17 static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
18 "KeyboardSharedMemory is bigger than the shared memory"); 18 "KeyboardSharedMemory is bigger than the shared memory");
@@ -21,13 +21,13 @@ Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_
21 emulated_devices = hid_core.GetEmulatedDevices(); 21 emulated_devices = hid_core.GetEmulatedDevices();
22} 22}
23 23
24Controller_Keyboard::~Controller_Keyboard() = default; 24Keyboard::~Keyboard() = default;
25 25
26void Controller_Keyboard::OnInit() {} 26void Keyboard::OnInit() {}
27 27
28void Controller_Keyboard::OnRelease() {} 28void Keyboard::OnRelease() {}
29 29
30void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 30void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
31 if (!IsControllerActivated()) { 31 if (!IsControllerActivated()) {
32 shared_memory->keyboard_lifo.buffer_count = 0; 32 shared_memory->keyboard_lifo.buffer_count = 0;
33 shared_memory->keyboard_lifo.buffer_tail = 0; 33 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;
14} // namespace Core::HID 14} // namespace Core::HID
15 15
16namespace Service::HID { 16namespace Service::HID {
17class Controller_Keyboard final : public ControllerBase { 17class Keyboard final : public ControllerBase {
18public: 18public:
19 explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 19 explicit Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
20 ~Controller_Keyboard() override; 20 ~Keyboard() override;
21 21
22 // Called when the controller is initialized 22 // Called when the controller is initialized
23 void OnInit() override; 23 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 @@
12namespace Service::HID { 12namespace Service::HID {
13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; 13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
14 14
15Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 15Mouse::Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
16 : ControllerBase{hid_core_} {
17 static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size, 16 static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size,
18 "MouseSharedMemory is bigger than the shared memory"); 17 "MouseSharedMemory is bigger than the shared memory");
19 shared_memory = std::construct_at( 18 shared_memory = std::construct_at(
@@ -21,12 +20,12 @@ Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared
21 emulated_devices = hid_core.GetEmulatedDevices(); 20 emulated_devices = hid_core.GetEmulatedDevices();
22} 21}
23 22
24Controller_Mouse::~Controller_Mouse() = default; 23Mouse::~Mouse() = default;
25 24
26void Controller_Mouse::OnInit() {} 25void Mouse::OnInit() {}
27void Controller_Mouse::OnRelease() {} 26void Mouse::OnRelease() {}
28 27
29void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 28void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
30 if (!IsControllerActivated()) { 29 if (!IsControllerActivated()) {
31 shared_memory->mouse_lifo.buffer_count = 0; 30 shared_memory->mouse_lifo.buffer_count = 0;
32 shared_memory->mouse_lifo.buffer_tail = 0; 31 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;
14} // namespace Core::HID 14} // namespace Core::HID
15 15
16namespace Service::HID { 16namespace Service::HID {
17class Controller_Mouse final : public ControllerBase { 17class Mouse final : public ControllerBase {
18public: 18public:
19 explicit Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 19 explicit Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
20 ~Controller_Mouse() override; 20 ~Mouse() override;
21 21
22 // Called when the controller is initialized 22 // Called when the controller is initialized
23 void OnInit() override; 23 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 @@
18#include "core/hle/kernel/k_readable_event.h" 18#include "core/hle/kernel/k_readable_event.h"
19#include "core/hle/service/hid/controllers/npad.h" 19#include "core/hle/service/hid/controllers/npad.h"
20#include "core/hle/service/hid/errors.h" 20#include "core/hle/service/hid/errors.h"
21#include "core/hle/service/hid/hid_util.h"
21#include "core/hle/service/kernel_helpers.h" 22#include "core/hle/service/kernel_helpers.h"
22 23
23namespace Service::HID { 24namespace Service::HID {
@@ -29,60 +30,8 @@ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
29 Core::HID::NpadIdType::Handheld, 30 Core::HID::NpadIdType::Handheld,
30}; 31};
31 32
32bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) { 33NPad::NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
33 switch (npad_id) { 34 KernelHelpers::ServiceContext& service_context_)
34 case Core::HID::NpadIdType::Player1:
35 case Core::HID::NpadIdType::Player2:
36 case Core::HID::NpadIdType::Player3:
37 case Core::HID::NpadIdType::Player4:
38 case Core::HID::NpadIdType::Player5:
39 case Core::HID::NpadIdType::Player6:
40 case Core::HID::NpadIdType::Player7:
41 case Core::HID::NpadIdType::Player8:
42 case Core::HID::NpadIdType::Other:
43 case Core::HID::NpadIdType::Handheld:
44 return true;
45 default:
46 LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id);
47 return false;
48 }
49}
50
51Result Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) {
52 const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
53 const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType;
54 const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
55
56 if (!npad_type) {
57 return VibrationInvalidStyleIndex;
58 }
59 if (!npad_id) {
60 return VibrationInvalidNpadId;
61 }
62 if (!device_index) {
63 return VibrationDeviceIndexOutOfRange;
64 }
65
66 return ResultSuccess;
67}
68
69Result Controller_NPad::VerifyValidSixAxisSensorHandle(
70 const Core::HID::SixAxisSensorHandle& device_handle) {
71 const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(device_handle.npad_id));
72 const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
73
74 if (!npad_id) {
75 return InvalidNpadId;
76 }
77 if (!device_index) {
78 return NpadDeviceIndexOutOfRange;
79 }
80
81 return ResultSuccess;
82}
83
84Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
85 KernelHelpers::ServiceContext& service_context_)
86 : ControllerBase{hid_core_}, service_context{service_context_} { 35 : ControllerBase{hid_core_}, service_context{service_context_} {
87 static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size); 36 static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size);
88 for (std::size_t i = 0; i < controller_data.size(); ++i) { 37 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
103 } 52 }
104} 53}
105 54
106Controller_NPad::~Controller_NPad() { 55NPad::~NPad() {
107 for (std::size_t i = 0; i < controller_data.size(); ++i) { 56 for (std::size_t i = 0; i < controller_data.size(); ++i) {
108 auto& controller = controller_data[i]; 57 auto& controller = controller_data[i];
109 controller.device->DeleteCallback(controller.callback_key); 58 controller.device->DeleteCallback(controller.callback_key);
@@ -111,8 +60,7 @@ Controller_NPad::~Controller_NPad() {
111 OnRelease(); 60 OnRelease();
112} 61}
113 62
114void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, 63void NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx) {
115 std::size_t controller_idx) {
116 if (type == Core::HID::ControllerTriggerType::All) { 64 if (type == Core::HID::ControllerTriggerType::All) {
117 ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx); 65 ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx);
118 ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); 66 ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx);
@@ -150,7 +98,7 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type,
150 } 98 }
151} 99}
152 100
153void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { 101void NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
154 auto& controller = GetControllerFromNpadIdType(npad_id); 102 auto& controller = GetControllerFromNpadIdType(npad_id);
155 if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) { 103 if (!IsControllerSupported(controller.device->GetNpadStyleIndex())) {
156 return; 104 return;
@@ -350,7 +298,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
350 hid_core.SetLastActiveController(npad_id); 298 hid_core.SetLastActiveController(npad_id);
351} 299}
352 300
353void Controller_NPad::OnInit() { 301void NPad::OnInit() {
354 if (!IsControllerActivated()) { 302 if (!IsControllerActivated()) {
355 return; 303 return;
356 } 304 }
@@ -384,7 +332,7 @@ void Controller_NPad::OnInit() {
384 } 332 }
385} 333}
386 334
387void Controller_NPad::WriteEmptyEntry(NpadInternalState* npad) { 335void NPad::WriteEmptyEntry(NpadInternalState* npad) {
388 NPadGenericState dummy_pad_state{}; 336 NPadGenericState dummy_pad_state{};
389 NpadGcTriggerState dummy_gc_state{}; 337 NpadGcTriggerState dummy_gc_state{};
390 dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1; 338 dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1;
@@ -405,7 +353,7 @@ void Controller_NPad::WriteEmptyEntry(NpadInternalState* npad) {
405 npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state); 353 npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state);
406} 354}
407 355
408void Controller_NPad::OnRelease() { 356void NPad::OnRelease() {
409 is_controller_initialized = false; 357 is_controller_initialized = false;
410 for (std::size_t i = 0; i < controller_data.size(); ++i) { 358 for (std::size_t i = 0; i < controller_data.size(); ++i) {
411 auto& controller = controller_data[i]; 359 auto& controller = controller_data[i];
@@ -416,7 +364,7 @@ void Controller_NPad::OnRelease() {
416 } 364 }
417} 365}
418 366
419void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { 367void NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
420 std::scoped_lock lock{mutex}; 368 std::scoped_lock lock{mutex};
421 auto& controller = GetControllerFromNpadIdType(npad_id); 369 auto& controller = GetControllerFromNpadIdType(npad_id);
422 const auto controller_type = controller.device->GetNpadStyleIndex(); 370 const auto controller_type = controller.device->GetNpadStyleIndex();
@@ -485,7 +433,7 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
485 } 433 }
486} 434}
487 435
488void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 436void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
489 if (!IsControllerActivated()) { 437 if (!IsControllerActivated()) {
490 return; 438 return;
491 } 439 }
@@ -615,134 +563,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
615 } 563 }
616} 564}
617 565
618void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) { 566void NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) {
619 if (!IsControllerActivated()) {
620 return;
621 }
622
623 for (std::size_t i = 0; i < controller_data.size(); ++i) {
624 auto& controller = controller_data[i];
625
626 const auto& controller_type = controller.device->GetNpadStyleIndex();
627
628 if (controller_type == Core::HID::NpadStyleIndex::None ||
629 !controller.device->IsConnected()) {
630 continue;
631 }
632
633 auto* npad = controller.shared_memory;
634 const auto& motion_state = controller.device->GetMotions();
635 auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
636 auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
637 auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
638 auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
639 auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
640 auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
641
642 // Clear previous state
643 sixaxis_fullkey_state = {};
644 sixaxis_handheld_state = {};
645 sixaxis_dual_left_state = {};
646 sixaxis_dual_right_state = {};
647 sixaxis_left_lifo_state = {};
648 sixaxis_right_lifo_state = {};
649
650 if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
651 controller.sixaxis_at_rest = true;
652 for (std::size_t e = 0; e < motion_state.size(); ++e) {
653 controller.sixaxis_at_rest =
654 controller.sixaxis_at_rest && motion_state[e].is_at_rest;
655 }
656 }
657
658 const auto set_motion_state = [&](SixAxisSensorState& state,
659 const Core::HID::ControllerMotion& hid_state) {
660 using namespace std::literals::chrono_literals;
661 static constexpr SixAxisSensorState default_motion_state = {
662 .delta_time = std::chrono::nanoseconds(5ms).count(),
663 .accel = {0, 0, -1.0f},
664 .orientation =
665 {
666 Common::Vec3f{1.0f, 0, 0},
667 Common::Vec3f{0, 1.0f, 0},
668 Common::Vec3f{0, 0, 1.0f},
669 },
670 .attribute = {1},
671 };
672 if (!controller.sixaxis_sensor_enabled) {
673 state = default_motion_state;
674 return;
675 }
676 if (!Settings::values.motion_enabled.GetValue()) {
677 state = default_motion_state;
678 return;
679 }
680 state.attribute.is_connected.Assign(1);
681 state.delta_time = std::chrono::nanoseconds(5ms).count();
682 state.accel = hid_state.accel;
683 state.gyro = hid_state.gyro;
684 state.rotation = hid_state.rotation;
685 state.orientation = hid_state.orientation;
686 };
687
688 switch (controller_type) {
689 case Core::HID::NpadStyleIndex::None:
690 ASSERT(false);
691 break;
692 case Core::HID::NpadStyleIndex::ProController:
693 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
694 break;
695 case Core::HID::NpadStyleIndex::Handheld:
696 set_motion_state(sixaxis_handheld_state, motion_state[0]);
697 break;
698 case Core::HID::NpadStyleIndex::JoyconDual:
699 set_motion_state(sixaxis_dual_left_state, motion_state[0]);
700 set_motion_state(sixaxis_dual_right_state, motion_state[1]);
701 break;
702 case Core::HID::NpadStyleIndex::JoyconLeft:
703 set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
704 break;
705 case Core::HID::NpadStyleIndex::JoyconRight:
706 set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
707 break;
708 case Core::HID::NpadStyleIndex::Pokeball:
709 using namespace std::literals::chrono_literals;
710 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
711 sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
712 break;
713 default:
714 break;
715 }
716
717 sixaxis_fullkey_state.sampling_number =
718 npad->sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
719 sixaxis_handheld_state.sampling_number =
720 npad->sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
721 sixaxis_dual_left_state.sampling_number =
722 npad->sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
723 sixaxis_dual_right_state.sampling_number =
724 npad->sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
725 sixaxis_left_lifo_state.sampling_number =
726 npad->sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
727 sixaxis_right_lifo_state.sampling_number =
728 npad->sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
729
730 if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
731 // This buffer only is updated on handheld on HW
732 npad->sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state);
733 } else {
734 // Handheld doesn't update this buffer on HW
735 npad->sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state);
736 }
737
738 npad->sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
739 npad->sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
740 npad->sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
741 npad->sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
742 }
743}
744
745void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) {
746 hid_core.SetSupportedStyleTag(style_set); 567 hid_core.SetSupportedStyleTag(style_set);
747 568
748 if (is_controller_initialized) { 569 if (is_controller_initialized) {
@@ -753,14 +574,14 @@ void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) {
753 is_controller_initialized = true; 574 is_controller_initialized = true;
754} 575}
755 576
756Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { 577Core::HID::NpadStyleTag NPad::GetSupportedStyleSet() const {
757 if (!is_controller_initialized) { 578 if (!is_controller_initialized) {
758 return {Core::HID::NpadStyleSet::None}; 579 return {Core::HID::NpadStyleSet::None};
759 } 580 }
760 return hid_core.GetSupportedStyleTag(); 581 return hid_core.GetSupportedStyleTag();
761} 582}
762 583
763Result Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) { 584Result NPad::SetSupportedNpadIdTypes(std::span<const u8> data) {
764 constexpr std::size_t max_number_npad_ids = 0xa; 585 constexpr std::size_t max_number_npad_ids = 0xa;
765 const auto length = data.size(); 586 const auto length = data.size();
766 ASSERT(length > 0 && (length % sizeof(u32)) == 0); 587 ASSERT(length > 0 && (length % sizeof(u32)) == 0);
@@ -776,17 +597,17 @@ Result Controller_NPad::SetSupportedNpadIdTypes(std::span<const u8> data) {
776 return ResultSuccess; 597 return ResultSuccess;
777} 598}
778 599
779void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { 600void NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
780 const auto copy_amount = supported_npad_id_types.size() * sizeof(u32); 601 const auto copy_amount = supported_npad_id_types.size() * sizeof(u32);
781 ASSERT(max_length <= copy_amount); 602 ASSERT(max_length <= copy_amount);
782 std::memcpy(data, supported_npad_id_types.data(), copy_amount); 603 std::memcpy(data, supported_npad_id_types.data(), copy_amount);
783} 604}
784 605
785std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const { 606std::size_t NPad::GetSupportedNpadIdTypesSize() const {
786 return supported_npad_id_types.size(); 607 return supported_npad_id_types.size();
787} 608}
788 609
789void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { 610void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
790 if (joy_hold_type != NpadJoyHoldType::Horizontal && 611 if (joy_hold_type != NpadJoyHoldType::Horizontal &&
791 joy_hold_type != NpadJoyHoldType::Vertical) { 612 joy_hold_type != NpadJoyHoldType::Vertical) {
792 LOG_ERROR(Service_HID, "Npad joy hold type needs to be valid, joy_hold_type={}", 613 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) {
796 hold_type = joy_hold_type; 617 hold_type = joy_hold_type;
797} 618}
798 619
799Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const { 620NPad::NpadJoyHoldType NPad::GetHoldType() const {
800 return hold_type; 621 return hold_type;
801} 622}
802 623
803void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { 624void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) {
804 if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) { 625 if (activation_mode >= NpadHandheldActivationMode::MaxActivationMode) {
805 ASSERT_MSG(false, "Activation mode should be always None, Single or Dual"); 626 ASSERT_MSG(false, "Activation mode should be always None, Single or Dual");
806 return; 627 return;
@@ -809,21 +630,20 @@ void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode a
809 handheld_activation_mode = activation_mode; 630 handheld_activation_mode = activation_mode;
810} 631}
811 632
812Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActivationMode() const { 633NPad::NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
813 return handheld_activation_mode; 634 return handheld_activation_mode;
814} 635}
815 636
816void Controller_NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) { 637void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
817 communication_mode = communication_mode_; 638 communication_mode = communication_mode_;
818} 639}
819 640
820Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode() const { 641NPad::NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
821 return communication_mode; 642 return communication_mode;
822} 643}
823 644
824bool Controller_NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, 645bool NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
825 NpadJoyDeviceType npad_device_type, 646 NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode) {
826 NpadJoyAssignmentMode assignment_mode) {
827 if (!IsNpadIdValid(npad_id)) { 647 if (!IsNpadIdValid(npad_id)) {
828 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 648 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
829 return false; 649 return false;
@@ -892,9 +712,8 @@ bool Controller_NPad::SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID:
892 return true; 712 return true;
893} 713}
894 714
895bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, 715bool NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
896 std::size_t device_index, 716 const Core::HID::VibrationValue& vibration_value) {
897 const Core::HID::VibrationValue& vibration_value) {
898 auto& controller = GetControllerFromNpadIdType(npad_id); 717 auto& controller = GetControllerFromNpadIdType(npad_id);
899 if (!controller.device->IsConnected()) { 718 if (!controller.device->IsConnected()) {
900 return false; 719 return false;
@@ -938,10 +757,9 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id,
938 return controller.device->SetVibration(device_index, vibration); 757 return controller.device->SetVibration(device_index, vibration);
939} 758}
940 759
941void Controller_NPad::VibrateController( 760void NPad::VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle,
942 const Core::HID::VibrationDeviceHandle& vibration_device_handle, 761 const Core::HID::VibrationValue& vibration_value) {
943 const Core::HID::VibrationValue& vibration_value) { 762 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
944 if (IsDeviceHandleValid(vibration_device_handle).IsError()) {
945 return; 763 return;
946 } 764 }
947 765
@@ -985,7 +803,7 @@ void Controller_NPad::VibrateController(
985 } 803 }
986} 804}
987 805
988void Controller_NPad::VibrateControllers( 806void NPad::VibrateControllers(
989 std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, 807 std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
990 std::span<const Core::HID::VibrationValue> vibration_values) { 808 std::span<const Core::HID::VibrationValue> vibration_values) {
991 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { 809 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
@@ -1002,9 +820,9 @@ void Controller_NPad::VibrateControllers(
1002 } 820 }
1003} 821}
1004 822
1005Core::HID::VibrationValue Controller_NPad::GetLastVibration( 823Core::HID::VibrationValue NPad::GetLastVibration(
1006 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { 824 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
1007 if (IsDeviceHandleValid(vibration_device_handle).IsError()) { 825 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
1008 return {}; 826 return {};
1009 } 827 }
1010 828
@@ -1013,9 +831,9 @@ Core::HID::VibrationValue Controller_NPad::GetLastVibration(
1013 return controller.vibration[device_index].latest_vibration_value; 831 return controller.vibration[device_index].latest_vibration_value;
1014} 832}
1015 833
1016void Controller_NPad::InitializeVibrationDevice( 834void NPad::InitializeVibrationDevice(
1017 const Core::HID::VibrationDeviceHandle& vibration_device_handle) { 835 const Core::HID::VibrationDeviceHandle& vibration_device_handle) {
1018 if (IsDeviceHandleValid(vibration_device_handle).IsError()) { 836 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
1019 return; 837 return;
1020 } 838 }
1021 839
@@ -1024,8 +842,8 @@ void Controller_NPad::InitializeVibrationDevice(
1024 InitializeVibrationDeviceAtIndex(npad_index, device_index); 842 InitializeVibrationDeviceAtIndex(npad_index, device_index);
1025} 843}
1026 844
1027void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, 845void NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id,
1028 std::size_t device_index) { 846 std::size_t device_index) {
1029 auto& controller = GetControllerFromNpadIdType(npad_id); 847 auto& controller = GetControllerFromNpadIdType(npad_id);
1030 if (!Settings::values.vibration_enabled.GetValue()) { 848 if (!Settings::values.vibration_enabled.GetValue()) {
1031 controller.vibration[device_index].device_mounted = false; 849 controller.vibration[device_index].device_mounted = false;
@@ -1036,13 +854,13 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npa
1036 controller.device->IsVibrationEnabled(device_index); 854 controller.device->IsVibrationEnabled(device_index);
1037} 855}
1038 856
1039void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { 857void NPad::SetPermitVibrationSession(bool permit_vibration_session) {
1040 permit_vibration_session_enabled = permit_vibration_session; 858 permit_vibration_session_enabled = permit_vibration_session;
1041} 859}
1042 860
1043bool Controller_NPad::IsVibrationDeviceMounted( 861bool NPad::IsVibrationDeviceMounted(
1044 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { 862 const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
1045 if (IsDeviceHandleValid(vibration_device_handle).IsError()) { 863 if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
1046 return false; 864 return false;
1047 } 865 }
1048 866
@@ -1051,7 +869,7 @@ bool Controller_NPad::IsVibrationDeviceMounted(
1051 return controller.vibration[device_index].device_mounted; 869 return controller.vibration[device_index].device_mounted;
1052} 870}
1053 871
1054Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { 872Kernel::KReadableEvent& NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) {
1055 if (!IsNpadIdValid(npad_id)) { 873 if (!IsNpadIdValid(npad_id)) {
1056 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 874 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1057 // Fallback to player 1 875 // Fallback to player 1
@@ -1063,18 +881,17 @@ Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::Npad
1063 return controller.styleset_changed_event->GetReadableEvent(); 881 return controller.styleset_changed_event->GetReadableEvent();
1064} 882}
1065 883
1066void Controller_NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { 884void NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const {
1067 const auto& controller = GetControllerFromNpadIdType(npad_id); 885 const auto& controller = GetControllerFromNpadIdType(npad_id);
1068 controller.styleset_changed_event->Signal(); 886 controller.styleset_changed_event->Signal();
1069} 887}
1070 888
1071void Controller_NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, 889void NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id) {
1072 Core::HID::NpadIdType npad_id) {
1073 UpdateControllerAt(controller, npad_id, true); 890 UpdateControllerAt(controller, npad_id, true);
1074} 891}
1075 892
1076void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, 893void NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, Core::HID::NpadIdType npad_id,
1077 Core::HID::NpadIdType npad_id, bool connected) { 894 bool connected) {
1078 auto& controller = GetControllerFromNpadIdType(npad_id); 895 auto& controller = GetControllerFromNpadIdType(npad_id);
1079 if (!connected) { 896 if (!connected) {
1080 DisconnectNpad(npad_id); 897 DisconnectNpad(npad_id);
@@ -1085,7 +902,7 @@ void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type,
1085 InitNewlyAddedController(npad_id); 902 InitNewlyAddedController(npad_id);
1086} 903}
1087 904
1088Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { 905Result NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
1089 if (!IsNpadIdValid(npad_id)) { 906 if (!IsNpadIdValid(npad_id)) {
1090 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 907 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1091 return InvalidNpadId; 908 return InvalidNpadId;
@@ -1134,54 +951,9 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) {
1134 return ResultSuccess; 951 return ResultSuccess;
1135} 952}
1136 953
1137Result Controller_NPad::SetGyroscopeZeroDriftMode( 954Result NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
1138 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
1139 Core::HID::GyroscopeZeroDriftMode drift_mode) {
1140 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1141 if (is_valid.IsError()) {
1142 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1143 return is_valid;
1144 }
1145
1146 auto& sixaxis = GetSixaxisState(sixaxis_handle);
1147 auto& controller = GetControllerFromHandle(sixaxis_handle);
1148 sixaxis.gyroscope_zero_drift_mode = drift_mode;
1149 controller.device->SetGyroscopeZeroDriftMode(drift_mode);
1150
1151 return ResultSuccess;
1152}
1153
1154Result Controller_NPad::GetGyroscopeZeroDriftMode(
1155 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
1156 Core::HID::GyroscopeZeroDriftMode& drift_mode) const {
1157 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1158 if (is_valid.IsError()) {
1159 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1160 return is_valid;
1161 }
1162
1163 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
1164 drift_mode = sixaxis.gyroscope_zero_drift_mode;
1165
1166 return ResultSuccess;
1167}
1168
1169Result Controller_NPad::IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
1170 bool& is_at_rest) const {
1171 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1172 if (is_valid.IsError()) {
1173 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1174 return is_valid;
1175 }
1176
1177 const auto& controller = GetControllerFromHandle(sixaxis_handle);
1178 is_at_rest = controller.sixaxis_at_rest;
1179 return ResultSuccess;
1180}
1181
1182Result Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
1183 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const { 955 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const {
1184 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); 956 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
1185 if (is_valid.IsError()) { 957 if (is_valid.IsError()) {
1186 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); 958 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1187 return is_valid; 959 return is_valid;
@@ -1192,65 +964,9 @@ Result Controller_NPad::IsFirmwareUpdateAvailableForSixAxisSensor(
1192 return ResultSuccess; 964 return ResultSuccess;
1193} 965}
1194 966
1195Result Controller_NPad::EnableSixAxisSensorUnalteredPassthrough( 967Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
1196 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) {
1197 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1198 if (is_valid.IsError()) {
1199 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1200 return is_valid;
1201 }
1202
1203 auto& sixaxis = GetSixaxisState(sixaxis_handle);
1204 sixaxis.unaltered_passtrough = is_enabled;
1205 return ResultSuccess;
1206}
1207
1208Result Controller_NPad::IsSixAxisSensorUnalteredPassthroughEnabled(
1209 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const {
1210 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1211 if (is_valid.IsError()) {
1212 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1213 return is_valid;
1214 }
1215
1216 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
1217 is_enabled = sixaxis.unaltered_passtrough;
1218 return ResultSuccess;
1219}
1220
1221Result Controller_NPad::LoadSixAxisSensorCalibrationParameter(
1222 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
1223 Core::HID::SixAxisSensorCalibrationParameter& calibration) const {
1224 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1225 if (is_valid.IsError()) {
1226 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1227 return is_valid;
1228 }
1229
1230 // TODO: Request this data to the controller. On error return 0xd8ca
1231 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
1232 calibration = sixaxis.calibration;
1233 return ResultSuccess;
1234}
1235
1236Result Controller_NPad::GetSixAxisSensorIcInformation(
1237 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
1238 Core::HID::SixAxisSensorIcInformation& ic_information) const {
1239 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1240 if (is_valid.IsError()) {
1241 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1242 return is_valid;
1243 }
1244
1245 // TODO: Request this data to the controller. On error return 0xd8ca
1246 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
1247 ic_information = sixaxis.ic_information;
1248 return ResultSuccess;
1249}
1250
1251Result Controller_NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
1252 const Core::HID::SixAxisSensorHandle& sixaxis_handle) { 968 const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
1253 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle); 969 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
1254 if (is_valid.IsError()) { 970 if (is_valid.IsError()) {
1255 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw); 971 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1256 return is_valid; 972 return is_valid;
@@ -1262,83 +978,32 @@ Result Controller_NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
1262 return ResultSuccess; 978 return ResultSuccess;
1263} 979}
1264 980
1265Result Controller_NPad::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, 981NPad::SixAxisLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
1266 bool sixaxis_status) { 982 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo;
1267 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1268 if (is_valid.IsError()) {
1269 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1270 return is_valid;
1271 }
1272
1273 auto& controller = GetControllerFromHandle(sixaxis_handle);
1274 controller.sixaxis_sensor_enabled = sixaxis_status;
1275 return ResultSuccess;
1276} 983}
1277 984
1278Result Controller_NPad::IsSixAxisSensorFusionEnabled( 985NPad::SixAxisLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
1279 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_fusion_enabled) const { 986 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo;
1280 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1281 if (is_valid.IsError()) {
1282 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1283 return is_valid;
1284 }
1285
1286 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
1287 is_fusion_enabled = sixaxis.is_fusion_enabled;
1288
1289 return ResultSuccess;
1290} 987}
1291Result Controller_NPad::SetSixAxisFusionEnabled(
1292 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_fusion_enabled) {
1293 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1294 if (is_valid.IsError()) {
1295 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1296 return is_valid;
1297 }
1298 988
1299 auto& sixaxis = GetSixaxisState(sixaxis_handle); 989NPad::SixAxisLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
1300 sixaxis.is_fusion_enabled = is_fusion_enabled; 990 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo;
1301
1302 return ResultSuccess;
1303} 991}
1304 992
1305Result Controller_NPad::SetSixAxisFusionParameters( 993NPad::SixAxisLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
1306 const Core::HID::SixAxisSensorHandle& sixaxis_handle, 994 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo;
1307 Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) {
1308 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1309 if (is_valid.IsError()) {
1310 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1311 return is_valid;
1312 }
1313
1314 const auto param1 = sixaxis_fusion_parameters.parameter1;
1315 if (param1 < 0.0f || param1 > 1.0f) {
1316 return InvalidSixAxisFusionRange;
1317 }
1318
1319 auto& sixaxis = GetSixaxisState(sixaxis_handle);
1320 sixaxis.fusion = sixaxis_fusion_parameters;
1321
1322 return ResultSuccess;
1323} 995}
1324 996
1325Result Controller_NPad::GetSixAxisFusionParameters( 997NPad::SixAxisLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
1326 const Core::HID::SixAxisSensorHandle& sixaxis_handle, 998 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo;
1327 Core::HID::SixAxisSensorFusionParameters& parameters) const { 999}
1328 const auto is_valid = VerifyValidSixAxisSensorHandle(sixaxis_handle);
1329 if (is_valid.IsError()) {
1330 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
1331 return is_valid;
1332 }
1333
1334 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
1335 parameters = sixaxis.fusion;
1336 1000
1337 return ResultSuccess; 1001NPad::SixAxisLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
1002 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo;
1338} 1003}
1339 1004
1340Result Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, 1005Result NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
1341 Core::HID::NpadIdType npad_id_2) { 1006 Core::HID::NpadIdType npad_id_2) {
1342 if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { 1007 if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
1343 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, 1008 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
1344 npad_id_2); 1009 npad_id_2);
@@ -1400,18 +1065,17 @@ Result Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
1400 return ResultSuccess; 1065 return ResultSuccess;
1401} 1066}
1402 1067
1403void Controller_NPad::StartLRAssignmentMode() { 1068void NPad::StartLRAssignmentMode() {
1404 // Nothing internally is used for lr assignment mode. Since we have the ability to set the 1069 // Nothing internally is used for lr assignment mode. Since we have the ability to set the
1405 // controller types from boot, it doesn't really matter about showing a selection screen 1070 // controller types from boot, it doesn't really matter about showing a selection screen
1406 is_in_lr_assignment_mode = true; 1071 is_in_lr_assignment_mode = true;
1407} 1072}
1408 1073
1409void Controller_NPad::StopLRAssignmentMode() { 1074void NPad::StopLRAssignmentMode() {
1410 is_in_lr_assignment_mode = false; 1075 is_in_lr_assignment_mode = false;
1411} 1076}
1412 1077
1413Result Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, 1078Result NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2) {
1414 Core::HID::NpadIdType npad_id_2) {
1415 if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { 1079 if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
1416 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, 1080 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
1417 npad_id_2); 1081 npad_id_2);
@@ -1442,8 +1106,7 @@ Result Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1,
1442 return ResultSuccess; 1106 return ResultSuccess;
1443} 1107}
1444 1108
1445Result Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id, 1109Result NPad::GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const {
1446 Core::HID::LedPattern& pattern) const {
1447 if (!IsNpadIdValid(npad_id)) { 1110 if (!IsNpadIdValid(npad_id)) {
1448 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 1111 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1449 return InvalidNpadId; 1112 return InvalidNpadId;
@@ -1453,8 +1116,8 @@ Result Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id,
1453 return ResultSuccess; 1116 return ResultSuccess;
1454} 1117}
1455 1118
1456Result Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, 1119Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
1457 bool& is_valid) const { 1120 bool& is_valid) const {
1458 if (!IsNpadIdValid(npad_id)) { 1121 if (!IsNpadIdValid(npad_id)) {
1459 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 1122 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1460 return InvalidNpadId; 1123 return InvalidNpadId;
@@ -1464,8 +1127,8 @@ Result Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::
1464 return ResultSuccess; 1127 return ResultSuccess;
1465} 1128}
1466 1129
1467Result Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled( 1130Result NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
1468 bool is_protection_enabled, Core::HID::NpadIdType npad_id) { 1131 Core::HID::NpadIdType npad_id) {
1469 if (!IsNpadIdValid(npad_id)) { 1132 if (!IsNpadIdValid(npad_id)) {
1470 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 1133 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1471 return InvalidNpadId; 1134 return InvalidNpadId;
@@ -1475,11 +1138,11 @@ Result Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(
1475 return ResultSuccess; 1138 return ResultSuccess;
1476} 1139}
1477 1140
1478void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { 1141void NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) {
1479 analog_stick_use_center_clamp = use_center_clamp; 1142 analog_stick_use_center_clamp = use_center_clamp;
1480} 1143}
1481 1144
1482void Controller_NPad::ClearAllConnectedControllers() { 1145void NPad::ClearAllConnectedControllers() {
1483 for (auto& controller : controller_data) { 1146 for (auto& controller : controller_data) {
1484 if (controller.device->IsConnected() && 1147 if (controller.device->IsConnected() &&
1485 controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { 1148 controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) {
@@ -1489,13 +1152,13 @@ void Controller_NPad::ClearAllConnectedControllers() {
1489 } 1152 }
1490} 1153}
1491 1154
1492void Controller_NPad::DisconnectAllConnectedControllers() { 1155void NPad::DisconnectAllConnectedControllers() {
1493 for (auto& controller : controller_data) { 1156 for (auto& controller : controller_data) {
1494 controller.device->Disconnect(); 1157 controller.device->Disconnect();
1495 } 1158 }
1496} 1159}
1497 1160
1498void Controller_NPad::ConnectAllDisconnectedControllers() { 1161void NPad::ConnectAllDisconnectedControllers() {
1499 for (auto& controller : controller_data) { 1162 for (auto& controller : controller_data) {
1500 if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None && 1163 if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None &&
1501 !controller.device->IsConnected()) { 1164 !controller.device->IsConnected()) {
@@ -1504,18 +1167,18 @@ void Controller_NPad::ConnectAllDisconnectedControllers() {
1504 } 1167 }
1505} 1168}
1506 1169
1507void Controller_NPad::ClearAllControllers() { 1170void NPad::ClearAllControllers() {
1508 for (auto& controller : controller_data) { 1171 for (auto& controller : controller_data) {
1509 controller.device->Disconnect(); 1172 controller.device->Disconnect();
1510 controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); 1173 controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None);
1511 } 1174 }
1512} 1175}
1513 1176
1514Core::HID::NpadButton Controller_NPad::GetAndResetPressState() { 1177Core::HID::NpadButton NPad::GetAndResetPressState() {
1515 return static_cast<Core::HID::NpadButton>(press_state.exchange(0)); 1178 return static_cast<Core::HID::NpadButton>(press_state.exchange(0));
1516} 1179}
1517 1180
1518void Controller_NPad::ApplyNpadSystemCommonPolicy() { 1181void NPad::ApplyNpadSystemCommonPolicy() {
1519 Core::HID::NpadStyleTag styletag{}; 1182 Core::HID::NpadStyleTag styletag{};
1520 styletag.fullkey.Assign(1); 1183 styletag.fullkey.Assign(1);
1521 styletag.handheld.Assign(1); 1184 styletag.handheld.Assign(1);
@@ -1540,7 +1203,7 @@ void Controller_NPad::ApplyNpadSystemCommonPolicy() {
1540 supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld; 1203 supported_npad_id_types[9] = Core::HID::NpadIdType::Handheld;
1541} 1204}
1542 1205
1543bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { 1206bool NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const {
1544 if (controller == Core::HID::NpadStyleIndex::Handheld) { 1207 if (controller == Core::HID::NpadStyleIndex::Handheld) {
1545 const bool support_handheld = 1208 const bool support_handheld =
1546 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), 1209 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(),
@@ -1591,51 +1254,50 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller
1591 return false; 1254 return false;
1592} 1255}
1593 1256
1594Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( 1257NPad::NpadControllerData& NPad::GetControllerFromHandle(
1595 const Core::HID::SixAxisSensorHandle& device_handle) { 1258 const Core::HID::VibrationDeviceHandle& device_handle) {
1596 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); 1259 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1597 return GetControllerFromNpadIdType(npad_id); 1260 return GetControllerFromNpadIdType(npad_id);
1598} 1261}
1599 1262
1600const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( 1263const NPad::NpadControllerData& NPad::GetControllerFromHandle(
1601 const Core::HID::SixAxisSensorHandle& device_handle) const { 1264 const Core::HID::VibrationDeviceHandle& device_handle) const {
1602 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); 1265 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1603 return GetControllerFromNpadIdType(npad_id); 1266 return GetControllerFromNpadIdType(npad_id);
1604} 1267}
1605 1268
1606Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( 1269NPad::NpadControllerData& NPad::GetControllerFromHandle(
1607 const Core::HID::VibrationDeviceHandle& device_handle) { 1270 const Core::HID::SixAxisSensorHandle& device_handle) {
1608 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); 1271 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1609 return GetControllerFromNpadIdType(npad_id); 1272 return GetControllerFromNpadIdType(npad_id);
1610} 1273}
1611 1274
1612const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( 1275const NPad::NpadControllerData& NPad::GetControllerFromHandle(
1613 const Core::HID::VibrationDeviceHandle& device_handle) const { 1276 const Core::HID::SixAxisSensorHandle& device_handle) const {
1614 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); 1277 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
1615 return GetControllerFromNpadIdType(npad_id); 1278 return GetControllerFromNpadIdType(npad_id);
1616} 1279}
1617 1280
1618Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( 1281NPad::NpadControllerData& NPad::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) {
1619 Core::HID::NpadIdType npad_id) {
1620 if (!IsNpadIdValid(npad_id)) { 1282 if (!IsNpadIdValid(npad_id)) {
1621 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 1283 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1622 npad_id = Core::HID::NpadIdType::Player1; 1284 npad_id = Core::HID::NpadIdType::Player1;
1623 } 1285 }
1624 const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); 1286 const auto npad_index = NpadIdTypeToIndex(npad_id);
1625 return controller_data[npad_index]; 1287 return controller_data[npad_index];
1626} 1288}
1627 1289
1628const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( 1290const NPad::NpadControllerData& NPad::GetControllerFromNpadIdType(
1629 Core::HID::NpadIdType npad_id) const { 1291 Core::HID::NpadIdType npad_id) const {
1630 if (!IsNpadIdValid(npad_id)) { 1292 if (!IsNpadIdValid(npad_id)) {
1631 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); 1293 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
1632 npad_id = Core::HID::NpadIdType::Player1; 1294 npad_id = Core::HID::NpadIdType::Player1;
1633 } 1295 }
1634 const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); 1296 const auto npad_index = NpadIdTypeToIndex(npad_id);
1635 return controller_data[npad_index]; 1297 return controller_data[npad_index];
1636} 1298}
1637 1299
1638Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties( 1300Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
1639 const Core::HID::SixAxisSensorHandle& sixaxis_handle) { 1301 const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
1640 auto& controller = GetControllerFromHandle(sixaxis_handle); 1302 auto& controller = GetControllerFromHandle(sixaxis_handle);
1641 switch (sixaxis_handle.npad_type) { 1303 switch (sixaxis_handle.npad_type) {
@@ -1658,7 +1320,7 @@ Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties(
1658 } 1320 }
1659} 1321}
1660 1322
1661const Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties( 1323const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
1662 const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { 1324 const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
1663 const auto& controller = GetControllerFromHandle(sixaxis_handle); 1325 const auto& controller = GetControllerFromHandle(sixaxis_handle);
1664 switch (sixaxis_handle.npad_type) { 1326 switch (sixaxis_handle.npad_type) {
@@ -1681,65 +1343,13 @@ const Core::HID::SixAxisSensorProperties& Controller_NPad::GetSixaxisProperties(
1681 } 1343 }
1682} 1344}
1683 1345
1684Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState( 1346NPad::AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
1685 const Core::HID::SixAxisSensorHandle& sixaxis_handle) { 1347 const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory;
1686 auto& controller = GetControllerFromHandle(sixaxis_handle);
1687 switch (sixaxis_handle.npad_type) {
1688 case Core::HID::NpadStyleIndex::ProController:
1689 case Core::HID::NpadStyleIndex::Pokeball:
1690 return controller.sixaxis_fullkey;
1691 case Core::HID::NpadStyleIndex::Handheld:
1692 return controller.sixaxis_handheld;
1693 case Core::HID::NpadStyleIndex::JoyconDual:
1694 if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
1695 return controller.sixaxis_dual_left;
1696 }
1697 return controller.sixaxis_dual_right;
1698 case Core::HID::NpadStyleIndex::JoyconLeft:
1699 return controller.sixaxis_left;
1700 case Core::HID::NpadStyleIndex::JoyconRight:
1701 return controller.sixaxis_right;
1702 default:
1703 return controller.sixaxis_unknown;
1704 }
1705}
1706
1707const Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
1708 const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
1709 const auto& controller = GetControllerFromHandle(sixaxis_handle);
1710 switch (sixaxis_handle.npad_type) {
1711 case Core::HID::NpadStyleIndex::ProController:
1712 case Core::HID::NpadStyleIndex::Pokeball:
1713 return controller.sixaxis_fullkey;
1714 case Core::HID::NpadStyleIndex::Handheld:
1715 return controller.sixaxis_handheld;
1716 case Core::HID::NpadStyleIndex::JoyconDual:
1717 if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
1718 return controller.sixaxis_dual_left;
1719 }
1720 return controller.sixaxis_dual_right;
1721 case Core::HID::NpadStyleIndex::JoyconLeft:
1722 return controller.sixaxis_left;
1723 case Core::HID::NpadStyleIndex::JoyconRight:
1724 return controller.sixaxis_right;
1725 default:
1726 return controller.sixaxis_unknown;
1727 }
1728}
1729
1730Controller_NPad::AppletDetailedUiType Controller_NPad::GetAppletDetailedUiType(
1731 Core::HID::NpadIdType npad_id) {
1732
1733 auto controller = GetControllerFromNpadIdType(npad_id);
1734 auto shared_memory = controller.shared_memory;
1735 Service::HID::Controller_NPad::AppletFooterUiType applet_footer_type =
1736 shared_memory->applet_footer_type;
1737 1348
1738 Controller_NPad::AppletDetailedUiType detailed_ui_type{ 1349 return {
1739 .ui_variant = 0, 1350 .ui_variant = 0,
1740 .footer = applet_footer_type, 1351 .footer = shared_memory->applet_footer_type,
1741 }; 1352 };
1742 return detailed_ui_type;
1743} 1353}
1744 1354
1745} // namespace Service::HID 1355} // 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 @@
10 10
11#include "common/bit_field.h" 11#include "common/bit_field.h"
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/vector_math.h"
14 13
15#include "core/hid/hid_types.h" 14#include "core/hid/hid_types.h"
16#include "core/hle/service/hid/controllers/controller_base.h" 15#include "core/hle/service/hid/controllers/controller_base.h"
@@ -34,11 +33,11 @@ union Result;
34 33
35namespace Service::HID { 34namespace Service::HID {
36 35
37class Controller_NPad final : public ControllerBase { 36class NPad final : public ControllerBase {
38public: 37public:
39 explicit Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, 38 explicit NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
40 KernelHelpers::ServiceContext& service_context_); 39 KernelHelpers::ServiceContext& service_context_);
41 ~Controller_NPad() override; 40 ~NPad() override;
42 41
43 // Called when the controller is initialized 42 // Called when the controller is initialized
44 void OnInit() override; 43 void OnInit() override;
@@ -49,9 +48,6 @@ public:
49 // When the controller is requesting an update for the shared memory 48 // When the controller is requesting an update for the shared memory
50 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 49 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
51 50
52 // When the controller is requesting a motion update for the shared memory
53 void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override;
54
55 // This is nn::hid::NpadJoyHoldType 51 // This is nn::hid::NpadJoyHoldType
56 enum class NpadJoyHoldType : u64 { 52 enum class NpadJoyHoldType : u64 {
57 Vertical = 0, 53 Vertical = 0,
@@ -133,6 +129,8 @@ public:
133 Revision3 = 3, 129 Revision3 = 3,
134 }; 130 };
135 131
132 using SixAxisLifo = Lifo<Core::HID::SixAxisSensorState, hid_entry_count>;
133
136 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); 134 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
137 Core::HID::NpadStyleTag GetSupportedStyleSet() const; 135 Core::HID::NpadStyleTag GetSupportedStyleSet() const;
138 136
@@ -185,37 +183,18 @@ public:
185 183
186 Result DisconnectNpad(Core::HID::NpadIdType npad_id); 184 Result DisconnectNpad(Core::HID::NpadIdType npad_id);
187 185
188 Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
189 Core::HID::GyroscopeZeroDriftMode drift_mode);
190 Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
191 Core::HID::GyroscopeZeroDriftMode& drift_mode) const;
192 Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
193 bool& is_at_rest) const;
194 Result IsFirmwareUpdateAvailableForSixAxisSensor( 186 Result IsFirmwareUpdateAvailableForSixAxisSensor(
195 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const; 187 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const;
196 Result EnableSixAxisSensorUnalteredPassthrough(
197 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled);
198 Result IsSixAxisSensorUnalteredPassthroughEnabled(
199 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const;
200 Result LoadSixAxisSensorCalibrationParameter(
201 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
202 Core::HID::SixAxisSensorCalibrationParameter& calibration) const;
203 Result GetSixAxisSensorIcInformation(
204 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
205 Core::HID::SixAxisSensorIcInformation& ic_information) const;
206 Result ResetIsSixAxisSensorDeviceNewlyAssigned( 188 Result ResetIsSixAxisSensorDeviceNewlyAssigned(
207 const Core::HID::SixAxisSensorHandle& sixaxis_handle); 189 const Core::HID::SixAxisSensorHandle& sixaxis_handle);
208 Result SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, 190
209 bool sixaxis_status); 191 SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
210 Result IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, 192 SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
211 bool& is_fusion_enabled) const; 193 SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
212 Result SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle, 194 SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
213 bool is_fusion_enabled); 195 SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
214 Result SetSixAxisFusionParameters( 196 SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
215 const Core::HID::SixAxisSensorHandle& sixaxis_handle, 197
216 Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters);
217 Result GetSixAxisFusionParameters(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
218 Core::HID::SixAxisSensorFusionParameters& parameters) const;
219 Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; 198 Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
220 Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, 199 Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
221 bool& is_enabled) const; 200 bool& is_enabled) const;
@@ -239,10 +218,6 @@ public:
239 218
240 void ApplyNpadSystemCommonPolicy(); 219 void ApplyNpadSystemCommonPolicy();
241 220
242 static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
243 static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
244 static Result VerifyValidSixAxisSensorHandle(
245 const Core::HID::SixAxisSensorHandle& device_handle);
246 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); 221 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
247 222
248private: 223private:
@@ -302,29 +277,6 @@ private:
302 }; 277 };
303 static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); 278 static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
304 279
305 // This is nn::hid::SixAxisSensorAttribute
306 struct SixAxisSensorAttribute {
307 union {
308 u32 raw{};
309 BitField<0, 1, u32> is_connected;
310 BitField<1, 1, u32> is_interpolated;
311 };
312 };
313 static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
314
315 // This is nn::hid::SixAxisSensorState
316 struct SixAxisSensorState {
317 s64 delta_time{};
318 s64 sampling_number{};
319 Common::Vec3f accel{};
320 Common::Vec3f gyro{};
321 Common::Vec3f rotation{};
322 std::array<Common::Vec3f, 3> orientation{};
323 SixAxisSensorAttribute attribute{};
324 INSERT_PADDING_BYTES(4); // Reserved
325 };
326 static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
327
328 // This is nn::hid::server::NpadGcTriggerState 280 // This is nn::hid::server::NpadGcTriggerState
329 struct NpadGcTriggerState { 281 struct NpadGcTriggerState {
330 s64 sampling_number{}; 282 s64 sampling_number{};
@@ -444,12 +396,12 @@ private:
444 Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{}; 396 Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{};
445 Lifo<NPadGenericState, hid_entry_count> palma_lifo{}; 397 Lifo<NPadGenericState, hid_entry_count> palma_lifo{};
446 Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{}; 398 Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{};
447 Lifo<SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{}; 399 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{};
448 Lifo<SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{}; 400 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{};
449 Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{}; 401 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{};
450 Lifo<SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{}; 402 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{};
451 Lifo<SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{}; 403 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{};
452 Lifo<SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{}; 404 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{};
453 DeviceType device_type{}; 405 DeviceType device_type{};
454 INSERT_PADDING_BYTES(0x4); // Reserved 406 INSERT_PADDING_BYTES(0x4); // Reserved
455 NPadSystemProperties system_properties{}; 407 NPadSystemProperties system_properties{};
@@ -483,16 +435,6 @@ private:
483 std::chrono::steady_clock::time_point last_vibration_timepoint{}; 435 std::chrono::steady_clock::time_point last_vibration_timepoint{};
484 }; 436 };
485 437
486 struct SixaxisParameters {
487 bool is_fusion_enabled{true};
488 bool unaltered_passtrough{false};
489 Core::HID::SixAxisSensorFusionParameters fusion{};
490 Core::HID::SixAxisSensorCalibrationParameter calibration{};
491 Core::HID::SixAxisSensorIcInformation ic_information{};
492 Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{
493 Core::HID::GyroscopeZeroDriftMode::Standard};
494 };
495
496 struct NpadControllerData { 438 struct NpadControllerData {
497 Kernel::KEvent* styleset_changed_event{}; 439 Kernel::KEvent* styleset_changed_event{};
498 NpadInternalState* shared_memory = nullptr; 440 NpadInternalState* shared_memory = nullptr;
@@ -506,27 +448,10 @@ private:
506 bool is_dual_left_connected{true}; 448 bool is_dual_left_connected{true};
507 bool is_dual_right_connected{true}; 449 bool is_dual_right_connected{true};
508 450
509 // Motion parameters
510 bool sixaxis_at_rest{true};
511 bool sixaxis_sensor_enabled{true};
512 SixaxisParameters sixaxis_fullkey{};
513 SixaxisParameters sixaxis_handheld{};
514 SixaxisParameters sixaxis_dual_left{};
515 SixaxisParameters sixaxis_dual_right{};
516 SixaxisParameters sixaxis_left{};
517 SixaxisParameters sixaxis_right{};
518 SixaxisParameters sixaxis_unknown{};
519
520 // Current pad state 451 // Current pad state
521 NPadGenericState npad_pad_state{}; 452 NPadGenericState npad_pad_state{};
522 NPadGenericState npad_libnx_state{}; 453 NPadGenericState npad_libnx_state{};
523 NpadGcTriggerState npad_trigger_state{}; 454 NpadGcTriggerState npad_trigger_state{};
524 SixAxisSensorState sixaxis_fullkey_state{};
525 SixAxisSensorState sixaxis_handheld_state{};
526 SixAxisSensorState sixaxis_dual_left_state{};
527 SixAxisSensorState sixaxis_dual_right_state{};
528 SixAxisSensorState sixaxis_left_lifo_state{};
529 SixAxisSensorState sixaxis_right_lifo_state{};
530 int callback_key{}; 455 int callback_key{};
531 }; 456 };
532 457
@@ -537,13 +462,13 @@ private:
537 void WriteEmptyEntry(NpadInternalState* npad); 462 void WriteEmptyEntry(NpadInternalState* npad);
538 463
539 NpadControllerData& GetControllerFromHandle( 464 NpadControllerData& GetControllerFromHandle(
540 const Core::HID::SixAxisSensorHandle& device_handle);
541 const NpadControllerData& GetControllerFromHandle(
542 const Core::HID::SixAxisSensorHandle& device_handle) const;
543 NpadControllerData& GetControllerFromHandle(
544 const Core::HID::VibrationDeviceHandle& device_handle); 465 const Core::HID::VibrationDeviceHandle& device_handle);
545 const NpadControllerData& GetControllerFromHandle( 466 const NpadControllerData& GetControllerFromHandle(
546 const Core::HID::VibrationDeviceHandle& device_handle) const; 467 const Core::HID::VibrationDeviceHandle& device_handle) const;
468 NpadControllerData& GetControllerFromHandle(
469 const Core::HID::SixAxisSensorHandle& device_handle);
470 const NpadControllerData& GetControllerFromHandle(
471 const Core::HID::SixAxisSensorHandle& device_handle) const;
547 NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); 472 NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
548 const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; 473 const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
549 474
@@ -551,9 +476,6 @@ private:
551 const Core::HID::SixAxisSensorHandle& device_handle); 476 const Core::HID::SixAxisSensorHandle& device_handle);
552 const Core::HID::SixAxisSensorProperties& GetSixaxisProperties( 477 const Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
553 const Core::HID::SixAxisSensorHandle& device_handle) const; 478 const Core::HID::SixAxisSensorHandle& device_handle) const;
554 SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle);
555 const SixaxisParameters& GetSixaxisState(
556 const Core::HID::SixAxisSensorHandle& device_handle) const;
557 479
558 std::atomic<u64> press_state{}; 480 std::atomic<u64> press_state{};
559 481
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 @@
12 12
13namespace Service::HID { 13namespace Service::HID {
14 14
15Controller_Palma::Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, 15Palma::Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
16 KernelHelpers::ServiceContext& service_context_) 16 KernelHelpers::ServiceContext& service_context_)
17 : ControllerBase{hid_core_}, service_context{service_context_} { 17 : ControllerBase{hid_core_}, service_context{service_context_} {
18 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); 18 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
19 operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent"); 19 operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");
20} 20}
21 21
22Controller_Palma::~Controller_Palma() { 22Palma::~Palma() {
23 service_context.CloseEvent(operation_complete_event); 23 service_context.CloseEvent(operation_complete_event);
24}; 24};
25 25
26void Controller_Palma::OnInit() {} 26void Palma::OnInit() {}
27 27
28void Controller_Palma::OnRelease() {} 28void Palma::OnRelease() {}
29 29
30void Controller_Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 30void Palma::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
31 if (!IsControllerActivated()) { 31 if (!IsControllerActivated()) {
32 return; 32 return;
33 } 33 }
34} 34}
35 35
36Result Controller_Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id, 36Result Palma::GetPalmaConnectionHandle(Core::HID::NpadIdType npad_id,
37 PalmaConnectionHandle& handle) { 37 PalmaConnectionHandle& handle) {
38 active_handle.npad_id = npad_id; 38 active_handle.npad_id = npad_id;
39 handle = active_handle; 39 handle = active_handle;
40 return ResultSuccess; 40 return ResultSuccess;
41} 41}
42 42
43Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) { 43Result Palma::InitializePalma(const PalmaConnectionHandle& handle) {
44 if (handle.npad_id != active_handle.npad_id) { 44 if (handle.npad_id != active_handle.npad_id) {
45 return InvalidPalmaHandle; 45 return InvalidPalmaHandle;
46 } 46 }
@@ -48,7 +48,7 @@ Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) {
48 return ResultSuccess; 48 return ResultSuccess;
49} 49}
50 50
51Kernel::KReadableEvent& Controller_Palma::AcquirePalmaOperationCompleteEvent( 51Kernel::KReadableEvent& Palma::AcquirePalmaOperationCompleteEvent(
52 const PalmaConnectionHandle& handle) const { 52 const PalmaConnectionHandle& handle) const {
53 if (handle.npad_id != active_handle.npad_id) { 53 if (handle.npad_id != active_handle.npad_id) {
54 LOG_ERROR(Service_HID, "Invalid npad id {}", handle.npad_id); 54 LOG_ERROR(Service_HID, "Invalid npad id {}", handle.npad_id);
@@ -56,9 +56,9 @@ Kernel::KReadableEvent& Controller_Palma::AcquirePalmaOperationCompleteEvent(
56 return operation_complete_event->GetReadableEvent(); 56 return operation_complete_event->GetReadableEvent();
57} 57}
58 58
59Result Controller_Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle, 59Result Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
60 PalmaOperationType& operation_type, 60 PalmaOperationType& operation_type,
61 PalmaOperationData& data) const { 61 PalmaOperationData& data) const {
62 if (handle.npad_id != active_handle.npad_id) { 62 if (handle.npad_id != active_handle.npad_id) {
63 return InvalidPalmaHandle; 63 return InvalidPalmaHandle;
64 } 64 }
@@ -67,8 +67,7 @@ Result Controller_Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& hand
67 return ResultSuccess; 67 return ResultSuccess;
68} 68}
69 69
70Result Controller_Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, 70Result Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity) {
71 u64 palma_activity) {
72 if (handle.npad_id != active_handle.npad_id) { 71 if (handle.npad_id != active_handle.npad_id) {
73 return InvalidPalmaHandle; 72 return InvalidPalmaHandle;
74 } 73 }
@@ -79,8 +78,7 @@ Result Controller_Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle,
79 return ResultSuccess; 78 return ResultSuccess;
80} 79}
81 80
82Result Controller_Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle, 81Result Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_) {
83 PalmaFrModeType fr_mode_) {
84 if (handle.npad_id != active_handle.npad_id) { 82 if (handle.npad_id != active_handle.npad_id) {
85 return InvalidPalmaHandle; 83 return InvalidPalmaHandle;
86 } 84 }
@@ -88,7 +86,7 @@ Result Controller_Palma::SetPalmaFrModeType(const PalmaConnectionHandle& handle,
88 return ResultSuccess; 86 return ResultSuccess;
89} 87}
90 88
91Result Controller_Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) { 89Result Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) {
92 if (handle.npad_id != active_handle.npad_id) { 90 if (handle.npad_id != active_handle.npad_id) {
93 return InvalidPalmaHandle; 91 return InvalidPalmaHandle;
94 } 92 }
@@ -99,25 +97,25 @@ Result Controller_Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) {
99 return ResultSuccess; 97 return ResultSuccess;
100} 98}
101 99
102Result Controller_Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) { 100Result Palma::EnablePalmaStep(const PalmaConnectionHandle& handle, bool is_enabled) {
103 if (handle.npad_id != active_handle.npad_id) { 101 if (handle.npad_id != active_handle.npad_id) {
104 return InvalidPalmaHandle; 102 return InvalidPalmaHandle;
105 } 103 }
106 return ResultSuccess; 104 return ResultSuccess;
107} 105}
108 106
109Result Controller_Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) { 107Result Palma::ResetPalmaStep(const PalmaConnectionHandle& handle) {
110 if (handle.npad_id != active_handle.npad_id) { 108 if (handle.npad_id != active_handle.npad_id) {
111 return InvalidPalmaHandle; 109 return InvalidPalmaHandle;
112 } 110 }
113 return ResultSuccess; 111 return ResultSuccess;
114} 112}
115 113
116void Controller_Palma::ReadPalmaApplicationSection() {} 114void Palma::ReadPalmaApplicationSection() {}
117 115
118void Controller_Palma::WritePalmaApplicationSection() {} 116void Palma::WritePalmaApplicationSection() {}
119 117
120Result Controller_Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) { 118Result Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) {
121 if (handle.npad_id != active_handle.npad_id) { 119 if (handle.npad_id != active_handle.npad_id) {
122 return InvalidPalmaHandle; 120 return InvalidPalmaHandle;
123 } 121 }
@@ -128,7 +126,7 @@ Result Controller_Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle
128 return ResultSuccess; 126 return ResultSuccess;
129} 127}
130 128
131Result Controller_Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) { 129Result Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) {
132 if (handle.npad_id != active_handle.npad_id) { 130 if (handle.npad_id != active_handle.npad_id) {
133 return InvalidPalmaHandle; 131 return InvalidPalmaHandle;
134 } 132 }
@@ -139,10 +137,9 @@ Result Controller_Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle&
139 return ResultSuccess; 137 return ResultSuccess;
140} 138}
141 139
142void Controller_Palma::WritePalmaActivityEntry() {} 140void Palma::WritePalmaActivityEntry() {}
143 141
144Result Controller_Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, 142Result Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle, u64 unknown) {
145 u64 unknown) {
146 if (handle.npad_id != active_handle.npad_id) { 143 if (handle.npad_id != active_handle.npad_id) {
147 return InvalidPalmaHandle; 144 return InvalidPalmaHandle;
148 } 145 }
@@ -153,8 +150,8 @@ Result Controller_Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandl
153 return ResultSuccess; 150 return ResultSuccess;
154} 151}
155 152
156Result Controller_Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave, 153Result Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWaveSet wave,
157 Common::ProcessAddress t_mem, u64 size) { 154 Common::ProcessAddress t_mem, u64 size) {
158 if (handle.npad_id != active_handle.npad_id) { 155 if (handle.npad_id != active_handle.npad_id) {
159 return InvalidPalmaHandle; 156 return InvalidPalmaHandle;
160 } 157 }
@@ -165,8 +162,8 @@ Result Controller_Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle
165 return ResultSuccess; 162 return ResultSuccess;
166} 163}
167 164
168Result Controller_Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle, 165Result Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle,
169 s32 database_id_version_) { 166 s32 database_id_version_) {
170 if (handle.npad_id != active_handle.npad_id) { 167 if (handle.npad_id != active_handle.npad_id) {
171 return InvalidPalmaHandle; 168 return InvalidPalmaHandle;
172 } 169 }
@@ -178,8 +175,7 @@ Result Controller_Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnec
178 return ResultSuccess; 175 return ResultSuccess;
179} 176}
180 177
181Result Controller_Palma::GetPalmaDataBaseIdentificationVersion( 178Result Palma::GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle& handle) {
182 const PalmaConnectionHandle& handle) {
183 if (handle.npad_id != active_handle.npad_id) { 179 if (handle.npad_id != active_handle.npad_id) {
184 return InvalidPalmaHandle; 180 return InvalidPalmaHandle;
185 } 181 }
@@ -191,26 +187,26 @@ Result Controller_Palma::GetPalmaDataBaseIdentificationVersion(
191 return ResultSuccess; 187 return ResultSuccess;
192} 188}
193 189
194void Controller_Palma::SuspendPalmaFeature() {} 190void Palma::SuspendPalmaFeature() {}
195 191
196Result Controller_Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const { 192Result Palma::GetPalmaOperationResult(const PalmaConnectionHandle& handle) const {
197 if (handle.npad_id != active_handle.npad_id) { 193 if (handle.npad_id != active_handle.npad_id) {
198 return InvalidPalmaHandle; 194 return InvalidPalmaHandle;
199 } 195 }
200 return operation.result; 196 return operation.result;
201} 197}
202void Controller_Palma::ReadPalmaPlayLog() {} 198void Palma::ReadPalmaPlayLog() {}
203 199
204void Controller_Palma::ResetPalmaPlayLog() {} 200void Palma::ResetPalmaPlayLog() {}
205 201
206void Controller_Palma::SetIsPalmaAllConnectable(bool is_all_connectable) { 202void Palma::SetIsPalmaAllConnectable(bool is_all_connectable) {
207 // If true controllers are able to be paired 203 // If true controllers are able to be paired
208 is_connectable = is_all_connectable; 204 is_connectable = is_all_connectable;
209} 205}
210 206
211void Controller_Palma::SetIsPalmaPairedConnectable() {} 207void Palma::SetIsPalmaPairedConnectable() {}
212 208
213Result Controller_Palma::PairPalma(const PalmaConnectionHandle& handle) { 209Result Palma::PairPalma(const PalmaConnectionHandle& handle) {
214 if (handle.npad_id != active_handle.npad_id) { 210 if (handle.npad_id != active_handle.npad_id) {
215 return InvalidPalmaHandle; 211 return InvalidPalmaHandle;
216 } 212 }
@@ -218,14 +214,14 @@ Result Controller_Palma::PairPalma(const PalmaConnectionHandle& handle) {
218 return ResultSuccess; 214 return ResultSuccess;
219} 215}
220 216
221void Controller_Palma::SetPalmaBoostMode(bool boost_mode) {} 217void Palma::SetPalmaBoostMode(bool boost_mode) {}
222 218
223void Controller_Palma::CancelWritePalmaWaveEntry() {} 219void Palma::CancelWritePalmaWaveEntry() {}
224 220
225void Controller_Palma::EnablePalmaBoostMode() {} 221void Palma::EnablePalmaBoostMode() {}
226 222
227void Controller_Palma::GetPalmaBluetoothAddress() {} 223void Palma::GetPalmaBluetoothAddress() {}
228 224
229void Controller_Palma::SetDisallowedPalmaConnection() {} 225void Palma::SetDisallowedPalmaConnection() {}
230 226
231} // namespace Service::HID 227} // 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;
23} // namespace Core::HID 23} // namespace Core::HID
24 24
25namespace Service::HID { 25namespace Service::HID {
26class Controller_Palma final : public ControllerBase { 26class Palma final : public ControllerBase {
27public: 27public:
28 using PalmaOperationData = std::array<u8, 0x140>; 28 using PalmaOperationData = std::array<u8, 0x140>;
29 29
@@ -97,9 +97,9 @@ public:
97 static_assert(sizeof(PalmaConnectionHandle) == 0x8, 97 static_assert(sizeof(PalmaConnectionHandle) == 0x8,
98 "PalmaConnectionHandle has incorrect size."); 98 "PalmaConnectionHandle has incorrect size.");
99 99
100 explicit Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, 100 explicit Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
101 KernelHelpers::ServiceContext& service_context_); 101 KernelHelpers::ServiceContext& service_context_);
102 ~Controller_Palma() override; 102 ~Palma() override;
103 103
104 // Called when the controller is initialized 104 // Called when the controller is initialized
105 void OnInit() override; 105 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 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#include <cstring>
5#include "common/common_types.h"
4#include "core/core.h" 6#include "core/core.h"
5#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/frontend/emu_window.h"
6#include "core/hid/emulated_console.h" 9#include "core/hid/emulated_console.h"
10#include "core/hid/emulated_devices.h"
7#include "core/hid/hid_core.h" 11#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/console_sixaxis.h" 12#include "core/hle/service/hid/controllers/seven_six_axis.h"
9#include "core/memory.h" 13#include "core/memory.h"
10 14
11namespace Service::HID { 15namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; 16SevenSixAxis::SevenSixAxis(Core::System& system_)
13
14Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_)
15 : ControllerBase{system_.HIDCore()}, system{system_} { 17 : ControllerBase{system_.HIDCore()}, system{system_} {
16 console = hid_core.GetEmulatedConsole(); 18 console = hid_core.GetEmulatedConsole();
17 static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
18 "ConsoleSharedMemory is bigger than the shared memory");
19 shared_memory = std::construct_at(
20 reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
21} 19}
22 20
23Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; 21SevenSixAxis::~SevenSixAxis() = default;
24
25void Controller_ConsoleSixAxis::OnInit() {}
26 22
27void Controller_ConsoleSixAxis::OnRelease() {} 23void SevenSixAxis::OnInit() {}
24void SevenSixAxis::OnRelease() {}
28 25
29void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 26void SevenSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
30 if (!IsControllerActivated() || transfer_memory == 0) { 27 if (!IsControllerActivated() || transfer_memory == 0) {
31 seven_sixaxis_lifo.buffer_count = 0; 28 seven_sixaxis_lifo.buffer_count = 0;
32 seven_sixaxis_lifo.buffer_tail = 0; 29 seven_sixaxis_lifo.buffer_tail = 0;
@@ -53,22 +50,17 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
53 -motion_status.quaternion.xyz.z, 50 -motion_status.quaternion.xyz.z,
54 }; 51 };
55 52
56 shared_memory->sampling_number++;
57 shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
58 shared_memory->verticalization_error = motion_status.verticalization_error;
59 shared_memory->gyro_bias = motion_status.gyro_bias;
60
61 // Update seven six axis transfer memory
62 seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); 53 seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state);
63 system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo, 54 system.ApplicationMemory().WriteBlock(transfer_memory, &seven_sixaxis_lifo,
64 sizeof(seven_sixaxis_lifo)); 55 sizeof(seven_sixaxis_lifo));
65} 56}
66 57
67void Controller_ConsoleSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) { 58void SevenSixAxis::SetTransferMemoryAddress(Common::ProcessAddress t_mem) {
68 transfer_memory = t_mem; 59 transfer_memory = t_mem;
69} 60}
70 61
71void Controller_ConsoleSixAxis::ResetTimestamp() { 62void SevenSixAxis::ResetTimestamp() {
72 last_saved_timestamp = last_global_timestamp; 63 last_saved_timestamp = last_global_timestamp;
73} 64}
65
74} // namespace Service::HID 66} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4#pragma once 4#pragma once
5 5
6#include <array> 6#include "common/common_types.h"
7
8#include "common/quaternion.h" 7#include "common/quaternion.h"
9#include "common/typed_address.h" 8#include "common/typed_address.h"
10#include "core/hle/service/hid/controllers/controller_base.h" 9#include "core/hle/service/hid/controllers/controller_base.h"
@@ -19,10 +18,10 @@ class EmulatedConsole;
19} // namespace Core::HID 18} // namespace Core::HID
20 19
21namespace Service::HID { 20namespace Service::HID {
22class Controller_ConsoleSixAxis final : public ControllerBase { 21class SevenSixAxis final : public ControllerBase {
23public: 22public:
24 explicit Controller_ConsoleSixAxis(Core::System& system_, u8* raw_shared_memory_); 23 explicit SevenSixAxis(Core::System& system_);
25 ~Controller_ConsoleSixAxis() override; 24 ~SevenSixAxis() override;
26 25
27 // Called when the controller is initialized 26 // Called when the controller is initialized
28 void OnInit() override; 27 void OnInit() override;
@@ -51,28 +50,16 @@ private:
51 }; 50 };
52 static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size"); 51 static_assert(sizeof(SevenSixAxisState) == 0x48, "SevenSixAxisState is an invalid size");
53 52
54 // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
55 struct ConsoleSharedMemory {
56 u64 sampling_number{};
57 bool is_seven_six_axis_sensor_at_rest{};
58 INSERT_PADDING_BYTES(3); // padding
59 f32 verticalization_error{};
60 Common::Vec3f gyro_bias{};
61 INSERT_PADDING_BYTES(4); // padding
62 };
63 static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
64
65 Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; 53 Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{};
66 static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); 54 static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size");
67 55
56 u64 last_saved_timestamp{};
57 u64 last_global_timestamp{};
58
68 SevenSixAxisState next_seven_sixaxis_state{}; 59 SevenSixAxisState next_seven_sixaxis_state{};
69 Common::ProcessAddress transfer_memory{}; 60 Common::ProcessAddress transfer_memory{};
70 ConsoleSharedMemory* shared_memory = nullptr;
71 Core::HID::EmulatedConsole* console = nullptr; 61 Core::HID::EmulatedConsole* console = nullptr;
72 62
73 u64 last_saved_timestamp{};
74 u64 last_global_timestamp{};
75
76 Core::System& system; 63 Core::System& system;
77}; 64};
78} // namespace Service::HID 65} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/common_types.h"
5#include "core/core_timing.h"
6#include "core/hid/emulated_controller.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/npad.h"
9#include "core/hle/service/hid/controllers/six_axis.h"
10#include "core/hle/service/hid/errors.h"
11#include "core/hle/service/hid/hid_util.h"
12
13namespace Service::HID {
14
15SixAxis::SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_)
16 : ControllerBase{hid_core_}, npad{npad_} {
17 for (std::size_t i = 0; i < controller_data.size(); ++i) {
18 auto& controller = controller_data[i];
19 controller.device = hid_core.GetEmulatedControllerByIndex(i);
20 }
21}
22
23SixAxis::~SixAxis() = default;
24
25void SixAxis::OnInit() {}
26void SixAxis::OnRelease() {}
27
28void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
29 if (!IsControllerActivated()) {
30 return;
31 }
32
33 for (std::size_t i = 0; i < controller_data.size(); ++i) {
34 auto& controller = controller_data[i];
35
36 const auto npad_id = IndexToNpadIdType(i);
37 const auto& controller_type = controller.device->GetNpadStyleIndex();
38
39 if (controller_type == Core::HID::NpadStyleIndex::None ||
40 !controller.device->IsConnected()) {
41 continue;
42 }
43
44 const auto& motion_state = controller.device->GetMotions();
45 auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state;
46 auto& sixaxis_handheld_state = controller.sixaxis_handheld_state;
47 auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state;
48 auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state;
49 auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state;
50 auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state;
51
52 auto& sixaxis_fullkey_lifo = npad->GetSixAxisFullkeyLifo(npad_id);
53 auto& sixaxis_handheld_lifo = npad->GetSixAxisHandheldLifo(npad_id);
54 auto& sixaxis_dual_left_lifo = npad->GetSixAxisDualLeftLifo(npad_id);
55 auto& sixaxis_dual_right_lifo = npad->GetSixAxisDualRightLifo(npad_id);
56 auto& sixaxis_left_lifo = npad->GetSixAxisLeftLifo(npad_id);
57 auto& sixaxis_right_lifo = npad->GetSixAxisRightLifo(npad_id);
58
59 // Clear previous state
60 sixaxis_fullkey_state = {};
61 sixaxis_handheld_state = {};
62 sixaxis_dual_left_state = {};
63 sixaxis_dual_right_state = {};
64 sixaxis_left_lifo_state = {};
65 sixaxis_right_lifo_state = {};
66
67 if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) {
68 controller.sixaxis_at_rest = true;
69 for (std::size_t e = 0; e < motion_state.size(); ++e) {
70 controller.sixaxis_at_rest =
71 controller.sixaxis_at_rest && motion_state[e].is_at_rest;
72 }
73 }
74
75 const auto set_motion_state = [&](Core::HID::SixAxisSensorState& state,
76 const Core::HID::ControllerMotion& hid_state) {
77 using namespace std::literals::chrono_literals;
78 static constexpr Core::HID::SixAxisSensorState default_motion_state = {
79 .delta_time = std::chrono::nanoseconds(5ms).count(),
80 .accel = {0, 0, -1.0f},
81 .orientation =
82 {
83 Common::Vec3f{1.0f, 0, 0},
84 Common::Vec3f{0, 1.0f, 0},
85 Common::Vec3f{0, 0, 1.0f},
86 },
87 .attribute = {1},
88 };
89 if (!controller.sixaxis_sensor_enabled) {
90 state = default_motion_state;
91 return;
92 }
93 if (!Settings::values.motion_enabled.GetValue()) {
94 state = default_motion_state;
95 return;
96 }
97 state.attribute.is_connected.Assign(1);
98 state.delta_time = std::chrono::nanoseconds(5ms).count();
99 state.accel = hid_state.accel;
100 state.gyro = hid_state.gyro;
101 state.rotation = hid_state.rotation;
102 state.orientation = hid_state.orientation;
103 };
104
105 switch (controller_type) {
106 case Core::HID::NpadStyleIndex::None:
107 ASSERT(false);
108 break;
109 case Core::HID::NpadStyleIndex::ProController:
110 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
111 break;
112 case Core::HID::NpadStyleIndex::Handheld:
113 set_motion_state(sixaxis_handheld_state, motion_state[0]);
114 break;
115 case Core::HID::NpadStyleIndex::JoyconDual:
116 set_motion_state(sixaxis_dual_left_state, motion_state[0]);
117 set_motion_state(sixaxis_dual_right_state, motion_state[1]);
118 break;
119 case Core::HID::NpadStyleIndex::JoyconLeft:
120 set_motion_state(sixaxis_left_lifo_state, motion_state[0]);
121 break;
122 case Core::HID::NpadStyleIndex::JoyconRight:
123 set_motion_state(sixaxis_right_lifo_state, motion_state[1]);
124 break;
125 case Core::HID::NpadStyleIndex::Pokeball:
126 using namespace std::literals::chrono_literals;
127 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
128 sixaxis_fullkey_state.delta_time = std::chrono::nanoseconds(15ms).count();
129 break;
130 default:
131 break;
132 }
133
134 sixaxis_fullkey_state.sampling_number =
135 sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
136 sixaxis_handheld_state.sampling_number =
137 sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
138 sixaxis_dual_left_state.sampling_number =
139 sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
140 sixaxis_dual_right_state.sampling_number =
141 sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
142 sixaxis_left_lifo_state.sampling_number =
143 sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
144 sixaxis_right_lifo_state.sampling_number =
145 sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
146
147 if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
148 // This buffer only is updated on handheld on HW
149 sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state);
150 } else {
151 // Handheld doesn't update this buffer on HW
152 sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state);
153 }
154
155 sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
156 sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
157 sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
158 sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
159 }
160}
161
162Result SixAxis::SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
163 Core::HID::GyroscopeZeroDriftMode drift_mode) {
164 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
165 if (is_valid.IsError()) {
166 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
167 return is_valid;
168 }
169
170 auto& sixaxis = GetSixaxisState(sixaxis_handle);
171 auto& controller = GetControllerFromHandle(sixaxis_handle);
172 sixaxis.gyroscope_zero_drift_mode = drift_mode;
173 controller.device->SetGyroscopeZeroDriftMode(drift_mode);
174
175 return ResultSuccess;
176}
177
178Result SixAxis::GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
179 Core::HID::GyroscopeZeroDriftMode& drift_mode) const {
180 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
181 if (is_valid.IsError()) {
182 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
183 return is_valid;
184 }
185
186 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
187 drift_mode = sixaxis.gyroscope_zero_drift_mode;
188
189 return ResultSuccess;
190}
191
192Result SixAxis::IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
193 bool& is_at_rest) const {
194 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
195 if (is_valid.IsError()) {
196 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
197 return is_valid;
198 }
199
200 const auto& controller = GetControllerFromHandle(sixaxis_handle);
201 is_at_rest = controller.sixaxis_at_rest;
202 return ResultSuccess;
203}
204
205Result SixAxis::LoadSixAxisSensorCalibrationParameter(
206 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
207 Core::HID::SixAxisSensorCalibrationParameter& calibration) const {
208 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
209 if (is_valid.IsError()) {
210 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
211 return is_valid;
212 }
213
214 // TODO: Request this data to the controller. On error return 0xd8ca
215 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
216 calibration = sixaxis.calibration;
217 return ResultSuccess;
218}
219
220Result SixAxis::GetSixAxisSensorIcInformation(
221 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
222 Core::HID::SixAxisSensorIcInformation& ic_information) const {
223 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
224 if (is_valid.IsError()) {
225 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
226 return is_valid;
227 }
228
229 // TODO: Request this data to the controller. On error return 0xd8ca
230 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
231 ic_information = sixaxis.ic_information;
232 return ResultSuccess;
233}
234
235Result SixAxis::EnableSixAxisSensorUnalteredPassthrough(
236 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled) {
237 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
238 if (is_valid.IsError()) {
239 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
240 return is_valid;
241 }
242
243 auto& sixaxis = GetSixaxisState(sixaxis_handle);
244 sixaxis.unaltered_passtrough = is_enabled;
245 return ResultSuccess;
246}
247
248Result SixAxis::IsSixAxisSensorUnalteredPassthroughEnabled(
249 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const {
250 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
251 if (is_valid.IsError()) {
252 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
253 return is_valid;
254 }
255
256 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
257 is_enabled = sixaxis.unaltered_passtrough;
258 return ResultSuccess;
259}
260
261Result SixAxis::SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
262 bool sixaxis_status) {
263 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
264 if (is_valid.IsError()) {
265 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
266 return is_valid;
267 }
268
269 auto& controller = GetControllerFromHandle(sixaxis_handle);
270 controller.sixaxis_sensor_enabled = sixaxis_status;
271 return ResultSuccess;
272}
273
274Result SixAxis::IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
275 bool& is_fusion_enabled) const {
276 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
277 if (is_valid.IsError()) {
278 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
279 return is_valid;
280 }
281
282 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
283 is_fusion_enabled = sixaxis.is_fusion_enabled;
284
285 return ResultSuccess;
286}
287Result SixAxis::SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
288 bool is_fusion_enabled) {
289 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
290 if (is_valid.IsError()) {
291 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
292 return is_valid;
293 }
294
295 auto& sixaxis = GetSixaxisState(sixaxis_handle);
296 sixaxis.is_fusion_enabled = is_fusion_enabled;
297
298 return ResultSuccess;
299}
300
301Result SixAxis::SetSixAxisFusionParameters(
302 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
303 Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) {
304 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
305 if (is_valid.IsError()) {
306 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
307 return is_valid;
308 }
309
310 const auto param1 = sixaxis_fusion_parameters.parameter1;
311 if (param1 < 0.0f || param1 > 1.0f) {
312 return InvalidSixAxisFusionRange;
313 }
314
315 auto& sixaxis = GetSixaxisState(sixaxis_handle);
316 sixaxis.fusion = sixaxis_fusion_parameters;
317
318 return ResultSuccess;
319}
320
321Result SixAxis::GetSixAxisFusionParameters(
322 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
323 Core::HID::SixAxisSensorFusionParameters& parameters) const {
324 const auto is_valid = IsSixaxisHandleValid(sixaxis_handle);
325 if (is_valid.IsError()) {
326 LOG_ERROR(Service_HID, "Invalid handle, error_code={}", is_valid.raw);
327 return is_valid;
328 }
329
330 const auto& sixaxis = GetSixaxisState(sixaxis_handle);
331 parameters = sixaxis.fusion;
332
333 return ResultSuccess;
334}
335
336SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
337 const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
338 auto& controller = GetControllerFromHandle(sixaxis_handle);
339 switch (sixaxis_handle.npad_type) {
340 case Core::HID::NpadStyleIndex::ProController:
341 case Core::HID::NpadStyleIndex::Pokeball:
342 return controller.sixaxis_fullkey;
343 case Core::HID::NpadStyleIndex::Handheld:
344 return controller.sixaxis_handheld;
345 case Core::HID::NpadStyleIndex::JoyconDual:
346 if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
347 return controller.sixaxis_dual_left;
348 }
349 return controller.sixaxis_dual_right;
350 case Core::HID::NpadStyleIndex::JoyconLeft:
351 return controller.sixaxis_left;
352 case Core::HID::NpadStyleIndex::JoyconRight:
353 return controller.sixaxis_right;
354 default:
355 return controller.sixaxis_unknown;
356 }
357}
358
359const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
360 const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
361 const auto& controller = GetControllerFromHandle(sixaxis_handle);
362 switch (sixaxis_handle.npad_type) {
363 case Core::HID::NpadStyleIndex::ProController:
364 case Core::HID::NpadStyleIndex::Pokeball:
365 return controller.sixaxis_fullkey;
366 case Core::HID::NpadStyleIndex::Handheld:
367 return controller.sixaxis_handheld;
368 case Core::HID::NpadStyleIndex::JoyconDual:
369 if (sixaxis_handle.device_index == Core::HID::DeviceIndex::Left) {
370 return controller.sixaxis_dual_left;
371 }
372 return controller.sixaxis_dual_right;
373 case Core::HID::NpadStyleIndex::JoyconLeft:
374 return controller.sixaxis_left;
375 case Core::HID::NpadStyleIndex::JoyconRight:
376 return controller.sixaxis_right;
377 default:
378 return controller.sixaxis_unknown;
379 }
380}
381
382SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle(
383 const Core::HID::SixAxisSensorHandle& device_handle) {
384 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
385 return GetControllerFromNpadIdType(npad_id);
386}
387
388const SixAxis::NpadControllerData& SixAxis::GetControllerFromHandle(
389 const Core::HID::SixAxisSensorHandle& device_handle) const {
390 const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
391 return GetControllerFromNpadIdType(npad_id);
392}
393
394SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) {
395 if (!IsNpadIdValid(npad_id)) {
396 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
397 npad_id = Core::HID::NpadIdType::Player1;
398 }
399 const auto npad_index = NpadIdTypeToIndex(npad_id);
400 return controller_data[npad_index];
401}
402
403const SixAxis::NpadControllerData& SixAxis::GetControllerFromNpadIdType(
404 Core::HID::NpadIdType npad_id) const {
405 if (!IsNpadIdValid(npad_id)) {
406 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
407 npad_id = Core::HID::NpadIdType::Player1;
408 }
409 const auto npad_index = NpadIdTypeToIndex(npad_id);
410 return controller_data[npad_index];
411}
412
413} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hid/hid_types.h"
8#include "core/hle/service/hid/controllers/controller_base.h"
9#include "core/hle/service/hid/ring_lifo.h"
10
11namespace Core::HID {
12class EmulatedController;
13} // namespace Core::HID
14
15namespace Service::HID {
16class NPad;
17
18class SixAxis final : public ControllerBase {
19public:
20 explicit SixAxis(Core::HID::HIDCore& hid_core_, std::shared_ptr<NPad> npad_);
21 ~SixAxis() override;
22
23 // Called when the controller is initialized
24 void OnInit() override;
25
26 // When the controller is released
27 void OnRelease() override;
28
29 // When the controller is requesting an update for the shared memory
30 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
31
32 Result SetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
33 Core::HID::GyroscopeZeroDriftMode drift_mode);
34 Result GetGyroscopeZeroDriftMode(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
35 Core::HID::GyroscopeZeroDriftMode& drift_mode) const;
36 Result IsSixAxisSensorAtRest(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
37 bool& is_at_rest) const;
38 Result EnableSixAxisSensorUnalteredPassthrough(
39 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool is_enabled);
40 Result IsSixAxisSensorUnalteredPassthroughEnabled(
41 const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_enabled) const;
42 Result LoadSixAxisSensorCalibrationParameter(
43 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
44 Core::HID::SixAxisSensorCalibrationParameter& calibration) const;
45 Result GetSixAxisSensorIcInformation(
46 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
47 Core::HID::SixAxisSensorIcInformation& ic_information) const;
48 Result SetSixAxisEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
49 bool sixaxis_status);
50 Result IsSixAxisSensorFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
51 bool& is_fusion_enabled) const;
52 Result SetSixAxisFusionEnabled(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
53 bool is_fusion_enabled);
54 Result SetSixAxisFusionParameters(
55 const Core::HID::SixAxisSensorHandle& sixaxis_handle,
56 Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters);
57 Result GetSixAxisFusionParameters(const Core::HID::SixAxisSensorHandle& sixaxis_handle,
58 Core::HID::SixAxisSensorFusionParameters& parameters) const;
59
60private:
61 static constexpr std::size_t NPAD_COUNT = 10;
62
63 struct SixaxisParameters {
64 bool is_fusion_enabled{true};
65 bool unaltered_passtrough{false};
66 Core::HID::SixAxisSensorFusionParameters fusion{};
67 Core::HID::SixAxisSensorCalibrationParameter calibration{};
68 Core::HID::SixAxisSensorIcInformation ic_information{};
69 Core::HID::GyroscopeZeroDriftMode gyroscope_zero_drift_mode{
70 Core::HID::GyroscopeZeroDriftMode::Standard};
71 };
72
73 struct NpadControllerData {
74 Core::HID::EmulatedController* device = nullptr;
75
76 // Motion parameters
77 bool sixaxis_at_rest{true};
78 bool sixaxis_sensor_enabled{true};
79 SixaxisParameters sixaxis_fullkey{};
80 SixaxisParameters sixaxis_handheld{};
81 SixaxisParameters sixaxis_dual_left{};
82 SixaxisParameters sixaxis_dual_right{};
83 SixaxisParameters sixaxis_left{};
84 SixaxisParameters sixaxis_right{};
85 SixaxisParameters sixaxis_unknown{};
86
87 // Current pad state
88 Core::HID::SixAxisSensorState sixaxis_fullkey_state{};
89 Core::HID::SixAxisSensorState sixaxis_handheld_state{};
90 Core::HID::SixAxisSensorState sixaxis_dual_left_state{};
91 Core::HID::SixAxisSensorState sixaxis_dual_right_state{};
92 Core::HID::SixAxisSensorState sixaxis_left_lifo_state{};
93 Core::HID::SixAxisSensorState sixaxis_right_lifo_state{};
94 int callback_key{};
95 };
96
97 SixaxisParameters& GetSixaxisState(const Core::HID::SixAxisSensorHandle& device_handle);
98 const SixaxisParameters& GetSixaxisState(
99 const Core::HID::SixAxisSensorHandle& device_handle) const;
100
101 NpadControllerData& GetControllerFromHandle(
102 const Core::HID::SixAxisSensorHandle& device_handle);
103 const NpadControllerData& GetControllerFromHandle(
104 const Core::HID::SixAxisSensorHandle& device_handle) const;
105 NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
106 const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
107
108 std::shared_ptr<NPad> npad;
109 std::array<NpadControllerData, NPAD_COUNT> controller_data{};
110};
111} // 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 @@
15namespace Service::HID { 15namespace Service::HID {
16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; 16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
17 17
18Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_, 18TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
19 u8* raw_shared_memory_)
20 : ControllerBase{hid_core_} { 19 : ControllerBase{hid_core_} {
21 static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size, 20 static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
22 "TouchSharedMemory is bigger than the shared memory"); 21 "TouchSharedMemory is bigger than the shared memory");
@@ -25,13 +24,13 @@ Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_,
25 console = hid_core.GetEmulatedConsole(); 24 console = hid_core.GetEmulatedConsole();
26} 25}
27 26
28Controller_Touchscreen::~Controller_Touchscreen() = default; 27TouchScreen::~TouchScreen() = default;
29 28
30void Controller_Touchscreen::OnInit() {} 29void TouchScreen::OnInit() {}
31 30
32void Controller_Touchscreen::OnRelease() {} 31void TouchScreen::OnRelease() {}
33 32
34void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 33void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
35 shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); 34 shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
36 35
37 if (!IsControllerActivated()) { 36 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;
14} // namespace Core::HID 14} // namespace Core::HID
15 15
16namespace Service::HID { 16namespace Service::HID {
17class Controller_Touchscreen final : public ControllerBase { 17class TouchScreen final : public ControllerBase {
18public: 18public:
19 explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 19 explicit TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
20 ~Controller_Touchscreen() override; 20 ~TouchScreen() override;
21 21
22 // Called when the controller is initialized 22 // Called when the controller is initialized
23 void OnInit() override; 23 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 @@
10namespace Service::HID { 10namespace Service::HID {
11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; 11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
12 12
13Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 13XPad::XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
14 : ControllerBase{hid_core_} {
15 static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size, 14 static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size,
16 "XpadSharedMemory is bigger than the shared memory"); 15 "XpadSharedMemory is bigger than the shared memory");
17 shared_memory = std::construct_at( 16 shared_memory = std::construct_at(
18 reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); 17 reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
19} 18}
20Controller_XPad::~Controller_XPad() = default; 19XPad::~XPad() = default;
21 20
22void Controller_XPad::OnInit() {} 21void XPad::OnInit() {}
23 22
24void Controller_XPad::OnRelease() {} 23void XPad::OnRelease() {}
25 24
26void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 25void XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
27 if (!IsControllerActivated()) { 26 if (!IsControllerActivated()) {
28 shared_memory->basic_xpad_lifo.buffer_count = 0; 27 shared_memory->basic_xpad_lifo.buffer_count = 0;
29 shared_memory->basic_xpad_lifo.buffer_tail = 0; 28 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 @@
10#include "core/hle/service/hid/ring_lifo.h" 10#include "core/hle/service/hid/ring_lifo.h"
11 11
12namespace Service::HID { 12namespace Service::HID {
13class Controller_XPad final : public ControllerBase { 13class XPad final : public ControllerBase {
14public: 14public:
15 explicit Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 15 explicit XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
16 ~Controller_XPad() override; 16 ~XPad() override;
17 17
18 // Called when the controller is initialized 18 // Called when the controller is initialized
19 void OnInit() override; 19 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 @@
12#include "core/hle/service/hid/errors.h" 12#include "core/hle/service/hid/errors.h"
13#include "core/hle/service/hid/hid_firmware_settings.h" 13#include "core/hle/service/hid/hid_firmware_settings.h"
14#include "core/hle/service/hid/hid_server.h" 14#include "core/hle/service/hid/hid_server.h"
15#include "core/hle/service/hid/hid_util.h"
15#include "core/hle/service/hid/resource_manager.h" 16#include "core/hle/service/hid/resource_manager.h"
16#include "core/hle/service/ipc_helpers.h" 17#include "core/hle/service/ipc_helpers.h"
17#include "core/memory.h" 18#include "core/memory.h"
18 19
19#include "core/hle/service/hid/controllers/console_sixaxis.h" 20#include "core/hle/service/hid/controllers/console_six_axis.h"
20#include "core/hle/service/hid/controllers/controller_base.h" 21#include "core/hle/service/hid/controllers/controller_base.h"
21#include "core/hle/service/hid/controllers/debug_pad.h" 22#include "core/hle/service/hid/controllers/debug_pad.h"
22#include "core/hle/service/hid/controllers/gesture.h" 23#include "core/hle/service/hid/controllers/gesture.h"
@@ -24,9 +25,9 @@
24#include "core/hle/service/hid/controllers/mouse.h" 25#include "core/hle/service/hid/controllers/mouse.h"
25#include "core/hle/service/hid/controllers/npad.h" 26#include "core/hle/service/hid/controllers/npad.h"
26#include "core/hle/service/hid/controllers/palma.h" 27#include "core/hle/service/hid/controllers/palma.h"
27#include "core/hle/service/hid/controllers/stubbed.h" 28#include "core/hle/service/hid/controllers/seven_six_axis.h"
29#include "core/hle/service/hid/controllers/six_axis.h"
28#include "core/hle/service/hid/controllers/touchscreen.h" 30#include "core/hle/service/hid/controllers/touchscreen.h"
29#include "core/hle/service/hid/controllers/xpad.h"
30 31
31namespace Service::HID { 32namespace Service::HID {
32 33
@@ -50,8 +51,7 @@ private:
50 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; 51 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
51 52
52 if (resource_manager != nullptr) { 53 if (resource_manager != nullptr) {
53 resource_manager->GetController<Controller_NPad>(HidController::NPad) 54 resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle);
54 .InitializeVibrationDevice(vibration_device_handle);
55 } 55 }
56 56
57 LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}", 57 LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
@@ -235,15 +235,14 @@ void IHidServer::ActivateDebugPad(HLERequestContext& ctx) {
235 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 235 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
236 236
237 Result result = ResultSuccess; 237 Result result = ResultSuccess;
238 auto& debug_pad = 238 auto debug_pad = GetResourceManager()->GetDebugPad();
239 GetResourceManager()->GetController<Controller_DebugPad>(HidController::DebugPad);
240 239
241 if (!firmware_settings->IsDeviceManaged()) { 240 if (!firmware_settings->IsDeviceManaged()) {
242 result = debug_pad.Activate(); 241 result = debug_pad->Activate();
243 } 242 }
244 243
245 if (result.IsSuccess()) { 244 if (result.IsSuccess()) {
246 result = debug_pad.Activate(applet_resource_user_id); 245 result = debug_pad->Activate(applet_resource_user_id);
247 } 246 }
248 247
249 IPC::ResponseBuilder rb{ctx, 2}; 248 IPC::ResponseBuilder rb{ctx, 2};
@@ -257,15 +256,14 @@ void IHidServer::ActivateTouchScreen(HLERequestContext& ctx) {
257 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 256 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
258 257
259 Result result = ResultSuccess; 258 Result result = ResultSuccess;
260 auto& touch_screen = 259 auto touch_screen = GetResourceManager()->GetTouchScreen();
261 GetResourceManager()->GetController<Controller_Touchscreen>(HidController::Touchscreen);
262 260
263 if (!firmware_settings->IsDeviceManaged()) { 261 if (!firmware_settings->IsDeviceManaged()) {
264 result = touch_screen.Activate(); 262 result = touch_screen->Activate();
265 } 263 }
266 264
267 if (result.IsSuccess()) { 265 if (result.IsSuccess()) {
268 result = touch_screen.Activate(applet_resource_user_id); 266 result = touch_screen->Activate(applet_resource_user_id);
269 } 267 }
270 268
271 IPC::ResponseBuilder rb{ctx, 2}; 269 IPC::ResponseBuilder rb{ctx, 2};
@@ -279,14 +277,14 @@ void IHidServer::ActivateMouse(HLERequestContext& ctx) {
279 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 277 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
280 278
281 Result result = ResultSuccess; 279 Result result = ResultSuccess;
282 auto& mouse = GetResourceManager()->GetController<Controller_Mouse>(HidController::Mouse); 280 auto mouse = GetResourceManager()->GetMouse();
283 281
284 if (!firmware_settings->IsDeviceManaged()) { 282 if (!firmware_settings->IsDeviceManaged()) {
285 result = mouse.Activate(); 283 result = mouse->Activate();
286 } 284 }
287 285
288 if (result.IsSuccess()) { 286 if (result.IsSuccess()) {
289 result = mouse.Activate(applet_resource_user_id); 287 result = mouse->Activate(applet_resource_user_id);
290 } 288 }
291 289
292 IPC::ResponseBuilder rb{ctx, 2}; 290 IPC::ResponseBuilder rb{ctx, 2};
@@ -300,15 +298,14 @@ void IHidServer::ActivateKeyboard(HLERequestContext& ctx) {
300 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 298 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
301 299
302 Result result = ResultSuccess; 300 Result result = ResultSuccess;
303 auto& keyboard = 301 auto keyboard = GetResourceManager()->GetKeyboard();
304 GetResourceManager()->GetController<Controller_Keyboard>(HidController::Keyboard);
305 302
306 if (!firmware_settings->IsDeviceManaged()) { 303 if (!firmware_settings->IsDeviceManaged()) {
307 result = keyboard.Activate(); 304 result = keyboard->Activate();
308 } 305 }
309 306
310 if (result.IsSuccess()) { 307 if (result.IsSuccess()) {
311 result = keyboard.Activate(applet_resource_user_id); 308 result = keyboard->Activate(applet_resource_user_id);
312 } 309 }
313 310
314 IPC::ResponseBuilder rb{ctx, 2}; 311 IPC::ResponseBuilder rb{ctx, 2};
@@ -502,8 +499,8 @@ void IHidServer::StartSixAxisSensor(HLERequestContext& ctx) {
502 499
503 const auto parameters{rp.PopRaw<Parameters>()}; 500 const auto parameters{rp.PopRaw<Parameters>()};
504 501
505 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 502 auto six_axis = GetResourceManager()->GetSixAxis();
506 const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, true); 503 const auto result = six_axis->SetSixAxisEnabled(parameters.sixaxis_handle, true);
507 504
508 LOG_DEBUG(Service_HID, 505 LOG_DEBUG(Service_HID,
509 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 506 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -525,8 +522,8 @@ void IHidServer::StopSixAxisSensor(HLERequestContext& ctx) {
525 522
526 const auto parameters{rp.PopRaw<Parameters>()}; 523 const auto parameters{rp.PopRaw<Parameters>()};
527 524
528 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 525 auto six_axis = GetResourceManager()->GetSixAxis();
529 const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, false); 526 const auto result = six_axis->SetSixAxisEnabled(parameters.sixaxis_handle, false);
530 527
531 LOG_DEBUG(Service_HID, 528 LOG_DEBUG(Service_HID,
532 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 529 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -549,9 +546,9 @@ void IHidServer::IsSixAxisSensorFusionEnabled(HLERequestContext& ctx) {
549 const auto parameters{rp.PopRaw<Parameters>()}; 546 const auto parameters{rp.PopRaw<Parameters>()};
550 547
551 bool is_enabled{}; 548 bool is_enabled{};
552 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 549 auto six_axis = GetResourceManager()->GetSixAxis();
553 const auto result = 550 const auto result =
554 controller.IsSixAxisSensorFusionEnabled(parameters.sixaxis_handle, is_enabled); 551 six_axis->IsSixAxisSensorFusionEnabled(parameters.sixaxis_handle, is_enabled);
555 552
556 LOG_DEBUG(Service_HID, 553 LOG_DEBUG(Service_HID,
557 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 554 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -575,9 +572,9 @@ void IHidServer::EnableSixAxisSensorFusion(HLERequestContext& ctx) {
575 572
576 const auto parameters{rp.PopRaw<Parameters>()}; 573 const auto parameters{rp.PopRaw<Parameters>()};
577 574
578 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 575 auto six_axis = GetResourceManager()->GetSixAxis();
579 const auto result = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle, 576 const auto result = six_axis->SetSixAxisFusionEnabled(parameters.sixaxis_handle,
580 parameters.enable_sixaxis_sensor_fusion); 577 parameters.enable_sixaxis_sensor_fusion);
581 578
582 LOG_DEBUG(Service_HID, 579 LOG_DEBUG(Service_HID,
583 "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " 580 "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
@@ -602,9 +599,9 @@ void IHidServer::SetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
602 599
603 const auto parameters{rp.PopRaw<Parameters>()}; 600 const auto parameters{rp.PopRaw<Parameters>()};
604 601
605 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 602 auto six_axis = GetResourceManager()->GetSixAxis();
606 const auto result = 603 const auto result =
607 controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion); 604 six_axis->SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion);
608 605
609 LOG_DEBUG(Service_HID, 606 LOG_DEBUG(Service_HID,
610 "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " 607 "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, "
@@ -629,10 +626,9 @@ void IHidServer::GetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
629 const auto parameters{rp.PopRaw<Parameters>()}; 626 const auto parameters{rp.PopRaw<Parameters>()};
630 627
631 Core::HID::SixAxisSensorFusionParameters fusion_parameters{}; 628 Core::HID::SixAxisSensorFusionParameters fusion_parameters{};
632 const auto& controller = 629 auto six_axis = GetResourceManager()->GetSixAxis();
633 GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
634 const auto result = 630 const auto result =
635 controller.GetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters); 631 six_axis->GetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
636 632
637 LOG_DEBUG(Service_HID, 633 LOG_DEBUG(Service_HID,
638 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 634 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -660,10 +656,10 @@ void IHidServer::ResetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
660 .parameter1 = 0.03f, 656 .parameter1 = 0.03f,
661 .parameter2 = 0.4f, 657 .parameter2 = 0.4f,
662 }; 658 };
663 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 659 auto six_axis = GetResourceManager()->GetSixAxis();
664 const auto result1 = 660 const auto result1 =
665 controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters); 661 six_axis->SetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
666 const auto result2 = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle, true); 662 const auto result2 = six_axis->SetSixAxisFusionEnabled(parameters.sixaxis_handle, true);
667 663
668 LOG_DEBUG(Service_HID, 664 LOG_DEBUG(Service_HID,
669 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 665 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -684,8 +680,8 @@ void IHidServer::SetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
684 const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()}; 680 const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()};
685 const auto applet_resource_user_id{rp.Pop<u64>()}; 681 const auto applet_resource_user_id{rp.Pop<u64>()};
686 682
687 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 683 auto six_axis = GetResourceManager()->GetSixAxis();
688 const auto result = controller.SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode); 684 const auto result = six_axis->SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode);
689 685
690 LOG_DEBUG(Service_HID, 686 LOG_DEBUG(Service_HID,
691 "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " 687 "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
@@ -709,8 +705,8 @@ void IHidServer::GetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
709 const auto parameters{rp.PopRaw<Parameters>()}; 705 const auto parameters{rp.PopRaw<Parameters>()};
710 706
711 auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard}; 707 auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
712 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 708 auto six_axis = GetResourceManager()->GetSixAxis();
713 const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); 709 const auto result = six_axis->GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
714 710
715 LOG_DEBUG(Service_HID, 711 LOG_DEBUG(Service_HID,
716 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 712 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -734,8 +730,8 @@ void IHidServer::ResetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
734 const auto parameters{rp.PopRaw<Parameters>()}; 730 const auto parameters{rp.PopRaw<Parameters>()};
735 731
736 const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard}; 732 const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
737 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 733 auto six_axis = GetResourceManager()->GetSixAxis();
738 const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); 734 const auto result = six_axis->SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
739 735
740 LOG_DEBUG(Service_HID, 736 LOG_DEBUG(Service_HID,
741 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 737 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -758,8 +754,8 @@ void IHidServer::IsSixAxisSensorAtRest(HLERequestContext& ctx) {
758 const auto parameters{rp.PopRaw<Parameters>()}; 754 const auto parameters{rp.PopRaw<Parameters>()};
759 755
760 bool is_at_rest{}; 756 bool is_at_rest{};
761 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 757 auto six_axis = GetResourceManager()->GetSixAxis();
762 controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest); 758 six_axis->IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
763 759
764 LOG_DEBUG(Service_HID, 760 LOG_DEBUG(Service_HID,
765 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 761 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -783,9 +779,9 @@ void IHidServer::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ct
783 const auto parameters{rp.PopRaw<Parameters>()}; 779 const auto parameters{rp.PopRaw<Parameters>()};
784 780
785 bool is_firmware_available{}; 781 bool is_firmware_available{};
786 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 782 auto controller = GetResourceManager()->GetNpad();
787 controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle, 783 controller->IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle,
788 is_firmware_available); 784 is_firmware_available);
789 785
790 LOG_WARNING( 786 LOG_WARNING(
791 Service_HID, 787 Service_HID,
@@ -809,9 +805,9 @@ void IHidServer::EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx)
809 805
810 const auto parameters{rp.PopRaw<Parameters>()}; 806 const auto parameters{rp.PopRaw<Parameters>()};
811 807
812 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 808 auto six_axis = GetResourceManager()->GetSixAxis();
813 const auto result = controller.EnableSixAxisSensorUnalteredPassthrough( 809 const auto result = six_axis->EnableSixAxisSensorUnalteredPassthrough(parameters.sixaxis_handle,
814 parameters.sixaxis_handle, parameters.enabled); 810 parameters.enabled);
815 811
816 LOG_DEBUG(Service_HID, 812 LOG_DEBUG(Service_HID,
817 "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, " 813 "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, "
@@ -836,8 +832,8 @@ void IHidServer::IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& c
836 const auto parameters{rp.PopRaw<Parameters>()}; 832 const auto parameters{rp.PopRaw<Parameters>()};
837 833
838 bool is_unaltered_sisxaxis_enabled{}; 834 bool is_unaltered_sisxaxis_enabled{};
839 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 835 auto six_axis = GetResourceManager()->GetSixAxis();
840 const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled( 836 const auto result = six_axis->IsSixAxisSensorUnalteredPassthroughEnabled(
841 parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled); 837 parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled);
842 838
843 LOG_DEBUG( 839 LOG_DEBUG(
@@ -863,9 +859,9 @@ void IHidServer::LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx) {
863 const auto parameters{rp.PopRaw<Parameters>()}; 859 const auto parameters{rp.PopRaw<Parameters>()};
864 860
865 Core::HID::SixAxisSensorCalibrationParameter calibration{}; 861 Core::HID::SixAxisSensorCalibrationParameter calibration{};
866 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 862 auto six_axis = GetResourceManager()->GetSixAxis();
867 const auto result = 863 const auto result =
868 controller.LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration); 864 six_axis->LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration);
869 865
870 LOG_WARNING( 866 LOG_WARNING(
871 Service_HID, 867 Service_HID,
@@ -893,9 +889,9 @@ void IHidServer::GetSixAxisSensorIcInformation(HLERequestContext& ctx) {
893 const auto parameters{rp.PopRaw<Parameters>()}; 889 const auto parameters{rp.PopRaw<Parameters>()};
894 890
895 Core::HID::SixAxisSensorIcInformation ic_information{}; 891 Core::HID::SixAxisSensorIcInformation ic_information{};
896 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 892 auto six_axis = GetResourceManager()->GetSixAxis();
897 const auto result = 893 const auto result =
898 controller.GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information); 894 six_axis->GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information);
899 895
900 LOG_WARNING( 896 LOG_WARNING(
901 Service_HID, 897 Service_HID,
@@ -922,9 +918,9 @@ void IHidServer::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx)
922 918
923 const auto parameters{rp.PopRaw<Parameters>()}; 919 const auto parameters{rp.PopRaw<Parameters>()};
924 920
925 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 921 auto controller = GetResourceManager()->GetNpad();
926 const auto result = 922 const auto result =
927 controller.ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle); 923 controller->ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle);
928 924
929 LOG_WARNING( 925 LOG_WARNING(
930 Service_HID, 926 Service_HID,
@@ -951,15 +947,15 @@ void IHidServer::ActivateGesture(HLERequestContext& ctx) {
951 parameters.basic_gesture_id, parameters.applet_resource_user_id); 947 parameters.basic_gesture_id, parameters.applet_resource_user_id);
952 948
953 Result result = ResultSuccess; 949 Result result = ResultSuccess;
954 auto& gesture = GetResourceManager()->GetController<Controller_Gesture>(HidController::Gesture); 950 auto gesture = GetResourceManager()->GetGesture();
955 951
956 if (!firmware_settings->IsDeviceManaged()) { 952 if (!firmware_settings->IsDeviceManaged()) {
957 result = gesture.Activate(); 953 result = gesture->Activate();
958 } 954 }
959 955
960 if (result.IsSuccess()) { 956 if (result.IsSuccess()) {
961 // TODO: Use gesture id here 957 // TODO: Use gesture id here
962 result = gesture.Activate(parameters.applet_resource_user_id); 958 result = gesture->Activate(parameters.applet_resource_user_id);
963 } 959 }
964 960
965 IPC::ResponseBuilder rb{ctx, 2}; 961 IPC::ResponseBuilder rb{ctx, 2};
@@ -977,9 +973,7 @@ void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) {
977 973
978 const auto parameters{rp.PopRaw<Parameters>()}; 974 const auto parameters{rp.PopRaw<Parameters>()};
979 975
980 GetResourceManager() 976 GetResourceManager()->GetNpad()->SetSupportedStyleSet({parameters.supported_styleset});
981 ->GetController<Controller_NPad>(HidController::NPad)
982 .SetSupportedStyleSet({parameters.supported_styleset});
983 977
984 LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}", 978 LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}",
985 parameters.supported_styleset, parameters.applet_resource_user_id); 979 parameters.supported_styleset, parameters.applet_resource_user_id);
@@ -996,19 +990,14 @@ void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) {
996 990
997 IPC::ResponseBuilder rb{ctx, 3}; 991 IPC::ResponseBuilder rb{ctx, 3};
998 rb.Push(ResultSuccess); 992 rb.Push(ResultSuccess);
999 rb.PushEnum(GetResourceManager() 993 rb.PushEnum(GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw);
1000 ->GetController<Controller_NPad>(HidController::NPad)
1001 .GetSupportedStyleSet()
1002 .raw);
1003} 994}
1004 995
1005void IHidServer::SetSupportedNpadIdType(HLERequestContext& ctx) { 996void IHidServer::SetSupportedNpadIdType(HLERequestContext& ctx) {
1006 IPC::RequestParser rp{ctx}; 997 IPC::RequestParser rp{ctx};
1007 const auto applet_resource_user_id{rp.Pop<u64>()}; 998 const auto applet_resource_user_id{rp.Pop<u64>()};
1008 999
1009 const auto result = GetResourceManager() 1000 const auto result = GetResourceManager()->GetNpad()->SetSupportedNpadIdTypes(ctx.ReadBuffer());
1010 ->GetController<Controller_NPad>(HidController::NPad)
1011 .SetSupportedNpadIdTypes(ctx.ReadBuffer());
1012 1001
1013 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1002 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1014 1003
@@ -1022,10 +1011,10 @@ void IHidServer::ActivateNpad(HLERequestContext& ctx) {
1022 1011
1023 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1012 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1024 1013
1025 auto& npad = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1014 auto npad = GetResourceManager()->GetNpad();
1026 1015
1027 // TODO: npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0); 1016 // TODO: npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0);
1028 const Result result = npad.Activate(applet_resource_user_id); 1017 const Result result = npad->Activate(applet_resource_user_id);
1029 1018
1030 IPC::ResponseBuilder rb{ctx, 2}; 1019 IPC::ResponseBuilder rb{ctx, 2};
1031 rb.Push(result); 1020 rb.Push(result);
@@ -1059,15 +1048,12 @@ void IHidServer::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) {
1059 parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown); 1048 parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
1060 1049
1061 // Games expect this event to be signaled after calling this function 1050 // Games expect this event to be signaled after calling this function
1062 GetResourceManager() 1051 GetResourceManager()->GetNpad()->SignalStyleSetChangedEvent(parameters.npad_id);
1063 ->GetController<Controller_NPad>(HidController::NPad)
1064 .SignalStyleSetChangedEvent(parameters.npad_id);
1065 1052
1066 IPC::ResponseBuilder rb{ctx, 2, 1}; 1053 IPC::ResponseBuilder rb{ctx, 2, 1};
1067 rb.Push(ResultSuccess); 1054 rb.Push(ResultSuccess);
1068 rb.PushCopyObjects(GetResourceManager() 1055 rb.PushCopyObjects(
1069 ->GetController<Controller_NPad>(HidController::NPad) 1056 GetResourceManager()->GetNpad()->GetStyleSetChangedEvent(parameters.npad_id));
1070 .GetStyleSetChangedEvent(parameters.npad_id));
1071} 1057}
1072 1058
1073void IHidServer::DisconnectNpad(HLERequestContext& ctx) { 1059void IHidServer::DisconnectNpad(HLERequestContext& ctx) {
@@ -1081,8 +1067,8 @@ void IHidServer::DisconnectNpad(HLERequestContext& ctx) {
1081 1067
1082 const auto parameters{rp.PopRaw<Parameters>()}; 1068 const auto parameters{rp.PopRaw<Parameters>()};
1083 1069
1084 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1070 auto controller = GetResourceManager()->GetNpad();
1085 controller.DisconnectNpad(parameters.npad_id); 1071 controller->DisconnectNpad(parameters.npad_id);
1086 1072
1087 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, 1073 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1088 parameters.applet_resource_user_id); 1074 parameters.applet_resource_user_id);
@@ -1096,8 +1082,8 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
1096 const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; 1082 const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
1097 1083
1098 Core::HID::LedPattern pattern{0, 0, 0, 0}; 1084 Core::HID::LedPattern pattern{0, 0, 0, 0};
1099 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1085 auto controller = GetResourceManager()->GetNpad();
1100 const auto result = controller.GetLedPattern(npad_id, pattern); 1086 const auto result = controller->GetLedPattern(npad_id, pattern);
1101 1087
1102 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); 1088 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
1103 1089
@@ -1109,7 +1095,7 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
1109void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { 1095void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
1110 IPC::RequestParser rp{ctx}; 1096 IPC::RequestParser rp{ctx};
1111 struct Parameters { 1097 struct Parameters {
1112 Controller_NPad::NpadRevision revision; 1098 NPad::NpadRevision revision;
1113 INSERT_PADDING_WORDS_NOINIT(1); 1099 INSERT_PADDING_WORDS_NOINIT(1);
1114 u64 applet_resource_user_id; 1100 u64 applet_resource_user_id;
1115 }; 1101 };
@@ -1120,10 +1106,10 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
1120 LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision, 1106 LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision,
1121 parameters.applet_resource_user_id); 1107 parameters.applet_resource_user_id);
1122 1108
1123 auto& npad = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1109 auto npad = GetResourceManager()->GetNpad();
1124 1110
1125 // TODO: npad->SetRevision(applet_resource_user_id, revision); 1111 // TODO: npad->SetRevision(applet_resource_user_id, revision);
1126 const auto result = npad.Activate(parameters.applet_resource_user_id); 1112 const auto result = npad->Activate(parameters.applet_resource_user_id);
1127 1113
1128 IPC::ResponseBuilder rb{ctx, 2}; 1114 IPC::ResponseBuilder rb{ctx, 2};
1129 rb.Push(result); 1115 rb.Push(result);
@@ -1132,11 +1118,9 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
1132void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) { 1118void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) {
1133 IPC::RequestParser rp{ctx}; 1119 IPC::RequestParser rp{ctx};
1134 const auto applet_resource_user_id{rp.Pop<u64>()}; 1120 const auto applet_resource_user_id{rp.Pop<u64>()};
1135 const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()}; 1121 const auto hold_type{rp.PopEnum<NPad::NpadJoyHoldType>()};
1136 1122
1137 GetResourceManager() 1123 GetResourceManager()->GetNpad()->SetHoldType(hold_type);
1138 ->GetController<Controller_NPad>(HidController::NPad)
1139 .SetHoldType(hold_type);
1140 1124
1141 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", 1125 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
1142 applet_resource_user_id, hold_type); 1126 applet_resource_user_id, hold_type);
@@ -1153,8 +1137,7 @@ void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) {
1153 1137
1154 IPC::ResponseBuilder rb{ctx, 4}; 1138 IPC::ResponseBuilder rb{ctx, 4};
1155 rb.Push(ResultSuccess); 1139 rb.Push(ResultSuccess);
1156 rb.PushEnum( 1140 rb.PushEnum(GetResourceManager()->GetNpad()->GetHoldType());
1157 GetResourceManager()->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
1158} 1141}
1159 1142
1160void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) { 1143void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) {
@@ -1169,10 +1152,9 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx)
1169 const auto parameters{rp.PopRaw<Parameters>()}; 1152 const auto parameters{rp.PopRaw<Parameters>()};
1170 1153
1171 Core::HID::NpadIdType new_npad_id{}; 1154 Core::HID::NpadIdType new_npad_id{};
1172 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1155 auto controller = GetResourceManager()->GetNpad();
1173 controller.SetNpadMode(new_npad_id, parameters.npad_id, 1156 controller->SetNpadMode(new_npad_id, parameters.npad_id, NPad::NpadJoyDeviceType::Left,
1174 Controller_NPad::NpadJoyDeviceType::Left, 1157 NPad::NpadJoyAssignmentMode::Single);
1175 Controller_NPad::NpadJoyAssignmentMode::Single);
1176 1158
1177 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, 1159 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1178 parameters.applet_resource_user_id); 1160 parameters.applet_resource_user_id);
@@ -1187,16 +1169,16 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
1187 Core::HID::NpadIdType npad_id; 1169 Core::HID::NpadIdType npad_id;
1188 INSERT_PADDING_WORDS_NOINIT(1); 1170 INSERT_PADDING_WORDS_NOINIT(1);
1189 u64 applet_resource_user_id; 1171 u64 applet_resource_user_id;
1190 Controller_NPad::NpadJoyDeviceType npad_joy_device_type; 1172 NPad::NpadJoyDeviceType npad_joy_device_type;
1191 }; 1173 };
1192 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); 1174 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1193 1175
1194 const auto parameters{rp.PopRaw<Parameters>()}; 1176 const auto parameters{rp.PopRaw<Parameters>()};
1195 1177
1196 Core::HID::NpadIdType new_npad_id{}; 1178 Core::HID::NpadIdType new_npad_id{};
1197 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1179 auto controller = GetResourceManager()->GetNpad();
1198 controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, 1180 controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
1199 Controller_NPad::NpadJoyAssignmentMode::Single); 1181 NPad::NpadJoyAssignmentMode::Single);
1200 1182
1201 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", 1183 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1202 parameters.npad_id, parameters.applet_resource_user_id, 1184 parameters.npad_id, parameters.applet_resource_user_id,
@@ -1218,9 +1200,8 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
1218 const auto parameters{rp.PopRaw<Parameters>()}; 1200 const auto parameters{rp.PopRaw<Parameters>()};
1219 1201
1220 Core::HID::NpadIdType new_npad_id{}; 1202 Core::HID::NpadIdType new_npad_id{};
1221 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1203 auto controller = GetResourceManager()->GetNpad();
1222 controller.SetNpadMode(new_npad_id, parameters.npad_id, {}, 1204 controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NPad::NpadJoyAssignmentMode::Dual);
1223 Controller_NPad::NpadJoyAssignmentMode::Dual);
1224 1205
1225 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, 1206 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1226 parameters.applet_resource_user_id); // Spams a lot when controller applet is open 1207 parameters.applet_resource_user_id); // Spams a lot when controller applet is open
@@ -1235,8 +1216,8 @@ void IHidServer::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) {
1235 const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; 1216 const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
1236 const auto applet_resource_user_id{rp.Pop<u64>()}; 1217 const auto applet_resource_user_id{rp.Pop<u64>()};
1237 1218
1238 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1219 auto controller = GetResourceManager()->GetNpad();
1239 const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2); 1220 const auto result = controller->MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
1240 1221
1241 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", 1222 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
1242 npad_id_1, npad_id_2, applet_resource_user_id); 1223 npad_id_1, npad_id_2, applet_resource_user_id);
@@ -1249,9 +1230,7 @@ void IHidServer::StartLrAssignmentMode(HLERequestContext& ctx) {
1249 IPC::RequestParser rp{ctx}; 1230 IPC::RequestParser rp{ctx};
1250 const auto applet_resource_user_id{rp.Pop<u64>()}; 1231 const auto applet_resource_user_id{rp.Pop<u64>()};
1251 1232
1252 GetResourceManager() 1233 GetResourceManager()->GetNpad()->StartLRAssignmentMode();
1253 ->GetController<Controller_NPad>(HidController::NPad)
1254 .StartLRAssignmentMode();
1255 1234
1256 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1235 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1257 1236
@@ -1263,9 +1242,7 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) {
1263 IPC::RequestParser rp{ctx}; 1242 IPC::RequestParser rp{ctx};
1264 const auto applet_resource_user_id{rp.Pop<u64>()}; 1243 const auto applet_resource_user_id{rp.Pop<u64>()};
1265 1244
1266 GetResourceManager() 1245 GetResourceManager()->GetNpad()->StopLRAssignmentMode();
1267 ->GetController<Controller_NPad>(HidController::NPad)
1268 .StopLRAssignmentMode();
1269 1246
1270 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1247 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1271 1248
@@ -1276,11 +1253,9 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) {
1276void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) { 1253void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
1277 IPC::RequestParser rp{ctx}; 1254 IPC::RequestParser rp{ctx};
1278 const auto applet_resource_user_id{rp.Pop<u64>()}; 1255 const auto applet_resource_user_id{rp.Pop<u64>()};
1279 const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()}; 1256 const auto activation_mode{rp.PopEnum<NPad::NpadHandheldActivationMode>()};
1280 1257
1281 GetResourceManager() 1258 GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode);
1282 ->GetController<Controller_NPad>(HidController::NPad)
1283 .SetNpadHandheldActivationMode(activation_mode);
1284 1259
1285 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}", 1260 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}",
1286 applet_resource_user_id, activation_mode); 1261 applet_resource_user_id, activation_mode);
@@ -1297,9 +1272,7 @@ void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) {
1297 1272
1298 IPC::ResponseBuilder rb{ctx, 4}; 1273 IPC::ResponseBuilder rb{ctx, 4};
1299 rb.Push(ResultSuccess); 1274 rb.Push(ResultSuccess);
1300 rb.PushEnum(GetResourceManager() 1275 rb.PushEnum(GetResourceManager()->GetNpad()->GetNpadHandheldActivationMode());
1301 ->GetController<Controller_NPad>(HidController::NPad)
1302 .GetNpadHandheldActivationMode());
1303} 1276}
1304 1277
1305void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) { 1278void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) {
@@ -1308,8 +1281,8 @@ void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) {
1308 const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()}; 1281 const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
1309 const auto applet_resource_user_id{rp.Pop<u64>()}; 1282 const auto applet_resource_user_id{rp.Pop<u64>()};
1310 1283
1311 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1284 auto controller = GetResourceManager()->GetNpad();
1312 const auto result = controller.SwapNpadAssignment(npad_id_1, npad_id_2); 1285 const auto result = controller->SwapNpadAssignment(npad_id_1, npad_id_2);
1313 1286
1314 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", 1287 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
1315 npad_id_1, npad_id_2, applet_resource_user_id); 1288 npad_id_1, npad_id_2, applet_resource_user_id);
@@ -1330,9 +1303,9 @@ void IHidServer::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext&
1330 const auto parameters{rp.PopRaw<Parameters>()}; 1303 const auto parameters{rp.PopRaw<Parameters>()};
1331 1304
1332 bool is_enabled = false; 1305 bool is_enabled = false;
1333 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1306 auto controller = GetResourceManager()->GetNpad();
1334 const auto result = 1307 const auto result =
1335 controller.IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled); 1308 controller->IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled);
1336 1309
1337 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", 1310 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
1338 parameters.npad_id, parameters.applet_resource_user_id); 1311 parameters.npad_id, parameters.applet_resource_user_id);
@@ -1354,8 +1327,8 @@ void IHidServer::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ct
1354 1327
1355 const auto parameters{rp.PopRaw<Parameters>()}; 1328 const auto parameters{rp.PopRaw<Parameters>()};
1356 1329
1357 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1330 auto controller = GetResourceManager()->GetNpad();
1358 const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled( 1331 const auto result = controller->SetUnintendedHomeButtonInputProtectionEnabled(
1359 parameters.is_enabled, parameters.npad_id); 1332 parameters.is_enabled, parameters.npad_id);
1360 1333
1361 LOG_DEBUG(Service_HID, 1334 LOG_DEBUG(Service_HID,
@@ -1372,17 +1345,17 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
1372 Core::HID::NpadIdType npad_id; 1345 Core::HID::NpadIdType npad_id;
1373 INSERT_PADDING_WORDS_NOINIT(1); 1346 INSERT_PADDING_WORDS_NOINIT(1);
1374 u64 applet_resource_user_id; 1347 u64 applet_resource_user_id;
1375 Controller_NPad::NpadJoyDeviceType npad_joy_device_type; 1348 NPad::NpadJoyDeviceType npad_joy_device_type;
1376 }; 1349 };
1377 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); 1350 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1378 1351
1379 const auto parameters{rp.PopRaw<Parameters>()}; 1352 const auto parameters{rp.PopRaw<Parameters>()};
1380 1353
1381 Core::HID::NpadIdType new_npad_id{}; 1354 Core::HID::NpadIdType new_npad_id{};
1382 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad); 1355 auto controller = GetResourceManager()->GetNpad();
1383 const auto is_reassigned = 1356 const auto is_reassigned =
1384 controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, 1357 controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
1385 Controller_NPad::NpadJoyAssignmentMode::Single); 1358 NPad::NpadJoyAssignmentMode::Single);
1386 1359
1387 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", 1360 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1388 parameters.npad_id, parameters.applet_resource_user_id, 1361 parameters.npad_id, parameters.applet_resource_user_id,
@@ -1405,9 +1378,8 @@ void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
1405 1378
1406 const auto parameters{rp.PopRaw<Parameters>()}; 1379 const auto parameters{rp.PopRaw<Parameters>()};
1407 1380
1408 GetResourceManager() 1381 GetResourceManager()->GetNpad()->SetAnalogStickUseCenterClamp(
1409 ->GetController<Controller_NPad>(HidController::NPad) 1382 parameters.analog_stick_use_center_clamp);
1410 .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
1411 1383
1412 LOG_WARNING(Service_HID, 1384 LOG_WARNING(Service_HID,
1413 "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}", 1385 "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
@@ -1451,8 +1423,7 @@ void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
1451void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { 1423void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
1452 IPC::RequestParser rp{ctx}; 1424 IPC::RequestParser rp{ctx};
1453 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; 1425 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
1454 const auto& controller = 1426 const auto controller = GetResourceManager()->GetNpad();
1455 GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1456 1427
1457 Core::HID::VibrationDeviceInfo vibration_device_info; 1428 Core::HID::VibrationDeviceInfo vibration_device_info;
1458 bool check_device_index = false; 1429 bool check_device_index = false;
@@ -1496,7 +1467,7 @@ void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
1496 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", 1467 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
1497 vibration_device_info.type, vibration_device_info.position); 1468 vibration_device_info.type, vibration_device_info.position);
1498 1469
1499 const auto result = controller.IsDeviceHandleValid(vibration_device_handle); 1470 const auto result = IsVibrationHandleValid(vibration_device_handle);
1500 if (result.IsError()) { 1471 if (result.IsError()) {
1501 IPC::ResponseBuilder rb{ctx, 2}; 1472 IPC::ResponseBuilder rb{ctx, 2};
1502 rb.Push(result); 1473 rb.Push(result);
@@ -1520,9 +1491,8 @@ void IHidServer::SendVibrationValue(HLERequestContext& ctx) {
1520 1491
1521 const auto parameters{rp.PopRaw<Parameters>()}; 1492 const auto parameters{rp.PopRaw<Parameters>()};
1522 1493
1523 GetResourceManager() 1494 GetResourceManager()->GetNpad()->VibrateController(parameters.vibration_device_handle,
1524 ->GetController<Controller_NPad>(HidController::NPad) 1495 parameters.vibration_value);
1525 .VibrateController(parameters.vibration_device_handle, parameters.vibration_value);
1526 1496
1527 LOG_DEBUG(Service_HID, 1497 LOG_DEBUG(Service_HID,
1528 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 1498 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@@ -1553,9 +1523,8 @@ void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) {
1553 1523
1554 IPC::ResponseBuilder rb{ctx, 6}; 1524 IPC::ResponseBuilder rb{ctx, 6};
1555 rb.Push(ResultSuccess); 1525 rb.Push(ResultSuccess);
1556 rb.PushRaw(GetResourceManager() 1526 rb.PushRaw(
1557 ->GetController<Controller_NPad>(HidController::NPad) 1527 GetResourceManager()->GetNpad()->GetLastVibration(parameters.vibration_device_handle));
1558 .GetLastVibration(parameters.vibration_device_handle));
1559} 1528}
1560 1529
1561void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) { 1530void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) {
@@ -1606,9 +1575,7 @@ void IHidServer::SendVibrationValues(HLERequestContext& ctx) {
1606 auto vibration_values = std::span( 1575 auto vibration_values = std::span(
1607 reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count); 1576 reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
1608 1577
1609 GetResourceManager() 1578 GetResourceManager()->GetNpad()->VibrateControllers(vibration_device_handles, vibration_values);
1610 ->GetController<Controller_NPad>(HidController::NPad)
1611 .VibrateControllers(vibration_device_handles, vibration_values);
1612 1579
1613 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1580 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1614 1581
@@ -1662,9 +1629,8 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
1662 } 1629 }
1663 }(); 1630 }();
1664 1631
1665 GetResourceManager() 1632 GetResourceManager()->GetNpad()->VibrateController(parameters.vibration_device_handle,
1666 ->GetController<Controller_NPad>(HidController::NPad) 1633 vibration_value);
1667 .VibrateController(parameters.vibration_device_handle, vibration_value);
1668 1634
1669 LOG_DEBUG(Service_HID, 1635 LOG_DEBUG(Service_HID,
1670 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " 1636 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
@@ -1688,9 +1654,8 @@ void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
1688 1654
1689 const auto parameters{rp.PopRaw<Parameters>()}; 1655 const auto parameters{rp.PopRaw<Parameters>()};
1690 1656
1691 const auto last_vibration = GetResourceManager() 1657 const auto last_vibration =
1692 ->GetController<Controller_NPad>(HidController::NPad) 1658 GetResourceManager()->GetNpad()->GetLastVibration(parameters.vibration_device_handle);
1693 .GetLastVibration(parameters.vibration_device_handle);
1694 1659
1695 const auto gc_erm_command = [last_vibration] { 1660 const auto gc_erm_command = [last_vibration] {
1696 if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { 1661 if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
@@ -1725,9 +1690,7 @@ void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) {
1725 IPC::RequestParser rp{ctx}; 1690 IPC::RequestParser rp{ctx};
1726 const auto applet_resource_user_id{rp.Pop<u64>()}; 1691 const auto applet_resource_user_id{rp.Pop<u64>()};
1727 1692
1728 GetResourceManager() 1693 GetResourceManager()->GetNpad()->SetPermitVibrationSession(true);
1729 ->GetController<Controller_NPad>(HidController::NPad)
1730 .SetPermitVibrationSession(true);
1731 1694
1732 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1695 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1733 1696
@@ -1736,9 +1699,7 @@ void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) {
1736} 1699}
1737 1700
1738void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) { 1701void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) {
1739 GetResourceManager() 1702 GetResourceManager()->GetNpad()->SetPermitVibrationSession(false);
1740 ->GetController<Controller_NPad>(HidController::NPad)
1741 .SetPermitVibrationSession(false);
1742 1703
1743 LOG_DEBUG(Service_HID, "called"); 1704 LOG_DEBUG(Service_HID, "called");
1744 1705
@@ -1765,9 +1726,8 @@ void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) {
1765 1726
1766 IPC::ResponseBuilder rb{ctx, 3}; 1727 IPC::ResponseBuilder rb{ctx, 3};
1767 rb.Push(ResultSuccess); 1728 rb.Push(ResultSuccess);
1768 rb.Push(GetResourceManager() 1729 rb.Push(GetResourceManager()->GetNpad()->IsVibrationDeviceMounted(
1769 ->GetController<Controller_NPad>(HidController::NPad) 1730 parameters.vibration_device_handle));
1770 .IsVibrationDeviceMounted(parameters.vibration_device_handle));
1771} 1731}
1772 1732
1773void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { 1733void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {
@@ -1777,15 +1737,14 @@ void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {
1777 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1737 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1778 1738
1779 Result result = ResultSuccess; 1739 Result result = ResultSuccess;
1780 auto console_sixaxis = GetResourceManager()->GetController<Controller_ConsoleSixAxis>( 1740 auto console_sixaxis = GetResourceManager()->GetConsoleSixAxis();
1781 HidController::ConsoleSixAxisSensor);
1782 1741
1783 if (!firmware_settings->IsDeviceManaged()) { 1742 if (!firmware_settings->IsDeviceManaged()) {
1784 result = console_sixaxis.Activate(); 1743 result = console_sixaxis->Activate();
1785 } 1744 }
1786 1745
1787 if (result.IsSuccess()) { 1746 if (result.IsSuccess()) {
1788 result = console_sixaxis.Activate(applet_resource_user_id); 1747 result = console_sixaxis->Activate(applet_resource_user_id);
1789 } 1748 }
1790 1749
1791 IPC::ResponseBuilder rb{ctx, 2}; 1750 IPC::ResponseBuilder rb{ctx, 2};
@@ -1839,15 +1798,14 @@ void IHidServer::ActivateSevenSixAxisSensor(HLERequestContext& ctx) {
1839 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1798 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1840 1799
1841 Result result = ResultSuccess; 1800 Result result = ResultSuccess;
1842 auto console_sixaxis = GetResourceManager()->GetController<Controller_ConsoleSixAxis>( 1801 auto seven_sixaxis = GetResourceManager()->GetSevenSixAxis();
1843 HidController::ConsoleSixAxisSensor);
1844 1802
1845 if (!firmware_settings->IsDeviceManaged()) { 1803 if (!firmware_settings->IsDeviceManaged()) {
1846 result = console_sixaxis.Activate(); 1804 result = seven_sixaxis->Activate();
1847 } 1805 }
1848 1806
1849 if (result.IsSuccess()) { 1807 if (result.IsSuccess()) {
1850 console_sixaxis.Activate(applet_resource_user_id); 1808 seven_sixaxis->Activate(applet_resource_user_id);
1851 } 1809 }
1852 1810
1853 IPC::ResponseBuilder rb{ctx, 2}; 1811 IPC::ResponseBuilder rb{ctx, 2};
@@ -1911,13 +1869,10 @@ void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
1911 ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size"); 1869 ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size");
1912 1870
1913 // Activate console six axis controller 1871 // Activate console six axis controller
1914 GetResourceManager() 1872 GetResourceManager()->GetConsoleSixAxis()->Activate();
1915 ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor) 1873 GetResourceManager()->GetSevenSixAxis()->Activate();
1916 .Activate();
1917 1874
1918 GetResourceManager() 1875 GetResourceManager()->GetSevenSixAxis()->SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
1919 ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1920 .SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
1921 1876
1922 LOG_WARNING(Service_HID, 1877 LOG_WARNING(Service_HID,
1923 "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, " 1878 "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
@@ -1943,9 +1898,7 @@ void IHidServer::ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx) {
1943 IPC::RequestParser rp{ctx}; 1898 IPC::RequestParser rp{ctx};
1944 const auto applet_resource_user_id{rp.Pop<u64>()}; 1899 const auto applet_resource_user_id{rp.Pop<u64>()};
1945 1900
1946 GetResourceManager() 1901 GetResourceManager()->GetSevenSixAxis()->ResetTimestamp();
1947 ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1948 .ResetTimestamp();
1949 1902
1950 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1903 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1951 1904
@@ -1977,9 +1930,9 @@ void IHidServer::GetPalmaConnectionHandle(HLERequestContext& ctx) {
1977 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", 1930 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
1978 parameters.npad_id, parameters.applet_resource_user_id); 1931 parameters.npad_id, parameters.applet_resource_user_id);
1979 1932
1980 Controller_Palma::PalmaConnectionHandle handle; 1933 Palma::PalmaConnectionHandle handle;
1981 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 1934 auto controller = GetResourceManager()->GetPalma();
1982 const auto result = controller.GetPalmaConnectionHandle(parameters.npad_id, handle); 1935 const auto result = controller->GetPalmaConnectionHandle(parameters.npad_id, handle);
1983 1936
1984 IPC::ResponseBuilder rb{ctx, 4}; 1937 IPC::ResponseBuilder rb{ctx, 4};
1985 rb.Push(result); 1938 rb.Push(result);
@@ -1988,12 +1941,12 @@ void IHidServer::GetPalmaConnectionHandle(HLERequestContext& ctx) {
1988 1941
1989void IHidServer::InitializePalma(HLERequestContext& ctx) { 1942void IHidServer::InitializePalma(HLERequestContext& ctx) {
1990 IPC::RequestParser rp{ctx}; 1943 IPC::RequestParser rp{ctx};
1991 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 1944 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
1992 1945
1993 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 1946 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
1994 1947
1995 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 1948 auto controller = GetResourceManager()->GetPalma();
1996 const auto result = controller.InitializePalma(connection_handle); 1949 const auto result = controller->InitializePalma(connection_handle);
1997 1950
1998 IPC::ResponseBuilder rb{ctx, 2}; 1951 IPC::ResponseBuilder rb{ctx, 2};
1999 rb.Push(result); 1952 rb.Push(result);
@@ -2001,27 +1954,27 @@ void IHidServer::InitializePalma(HLERequestContext& ctx) {
2001 1954
2002void IHidServer::AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx) { 1955void IHidServer::AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx) {
2003 IPC::RequestParser rp{ctx}; 1956 IPC::RequestParser rp{ctx};
2004 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 1957 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2005 1958
2006 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 1959 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2007 1960
2008 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 1961 auto controller = GetResourceManager()->GetPalma();
2009 1962
2010 IPC::ResponseBuilder rb{ctx, 2, 1}; 1963 IPC::ResponseBuilder rb{ctx, 2, 1};
2011 rb.Push(ResultSuccess); 1964 rb.Push(ResultSuccess);
2012 rb.PushCopyObjects(controller.AcquirePalmaOperationCompleteEvent(connection_handle)); 1965 rb.PushCopyObjects(controller->AcquirePalmaOperationCompleteEvent(connection_handle));
2013} 1966}
2014 1967
2015void IHidServer::GetPalmaOperationInfo(HLERequestContext& ctx) { 1968void IHidServer::GetPalmaOperationInfo(HLERequestContext& ctx) {
2016 IPC::RequestParser rp{ctx}; 1969 IPC::RequestParser rp{ctx};
2017 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 1970 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2018 1971
2019 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 1972 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2020 1973
2021 Controller_Palma::PalmaOperationType operation_type; 1974 Palma::PalmaOperationType operation_type;
2022 Controller_Palma::PalmaOperationData data; 1975 Palma::PalmaOperationData data;
2023 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 1976 auto controller = GetResourceManager()->GetPalma();
2024 const auto result = controller.GetPalmaOperationInfo(connection_handle, operation_type, data); 1977 const auto result = controller->GetPalmaOperationInfo(connection_handle, operation_type, data);
2025 1978
2026 if (result.IsError()) { 1979 if (result.IsError()) {
2027 IPC::ResponseBuilder rb{ctx, 2}; 1980 IPC::ResponseBuilder rb{ctx, 2};
@@ -2036,14 +1989,14 @@ void IHidServer::GetPalmaOperationInfo(HLERequestContext& ctx) {
2036 1989
2037void IHidServer::PlayPalmaActivity(HLERequestContext& ctx) { 1990void IHidServer::PlayPalmaActivity(HLERequestContext& ctx) {
2038 IPC::RequestParser rp{ctx}; 1991 IPC::RequestParser rp{ctx};
2039 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 1992 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2040 const auto palma_activity{rp.Pop<u64>()}; 1993 const auto palma_activity{rp.Pop<u64>()};
2041 1994
2042 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, palma_activity={}", 1995 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, palma_activity={}",
2043 connection_handle.npad_id, palma_activity); 1996 connection_handle.npad_id, palma_activity);
2044 1997
2045 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 1998 auto controller = GetResourceManager()->GetPalma();
2046 const auto result = controller.PlayPalmaActivity(connection_handle, palma_activity); 1999 const auto result = controller->PlayPalmaActivity(connection_handle, palma_activity);
2047 2000
2048 IPC::ResponseBuilder rb{ctx, 2}; 2001 IPC::ResponseBuilder rb{ctx, 2};
2049 rb.Push(result); 2002 rb.Push(result);
@@ -2051,14 +2004,14 @@ void IHidServer::PlayPalmaActivity(HLERequestContext& ctx) {
2051 2004
2052void IHidServer::SetPalmaFrModeType(HLERequestContext& ctx) { 2005void IHidServer::SetPalmaFrModeType(HLERequestContext& ctx) {
2053 IPC::RequestParser rp{ctx}; 2006 IPC::RequestParser rp{ctx};
2054 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2007 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2055 const auto fr_mode{rp.PopEnum<Controller_Palma::PalmaFrModeType>()}; 2008 const auto fr_mode{rp.PopEnum<Palma::PalmaFrModeType>()};
2056 2009
2057 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, fr_mode={}", 2010 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, fr_mode={}",
2058 connection_handle.npad_id, fr_mode); 2011 connection_handle.npad_id, fr_mode);
2059 2012
2060 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 2013 auto controller = GetResourceManager()->GetPalma();
2061 const auto result = controller.SetPalmaFrModeType(connection_handle, fr_mode); 2014 const auto result = controller->SetPalmaFrModeType(connection_handle, fr_mode);
2062 2015
2063 IPC::ResponseBuilder rb{ctx, 2}; 2016 IPC::ResponseBuilder rb{ctx, 2};
2064 rb.Push(result); 2017 rb.Push(result);
@@ -2066,12 +2019,12 @@ void IHidServer::SetPalmaFrModeType(HLERequestContext& ctx) {
2066 2019
2067void IHidServer::ReadPalmaStep(HLERequestContext& ctx) { 2020void IHidServer::ReadPalmaStep(HLERequestContext& ctx) {
2068 IPC::RequestParser rp{ctx}; 2021 IPC::RequestParser rp{ctx};
2069 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2022 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2070 2023
2071 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 2024 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2072 2025
2073 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 2026 auto controller = GetResourceManager()->GetPalma();
2074 const auto result = controller.ReadPalmaStep(connection_handle); 2027 const auto result = controller->ReadPalmaStep(connection_handle);
2075 2028
2076 IPC::ResponseBuilder rb{ctx, 2}; 2029 IPC::ResponseBuilder rb{ctx, 2};
2077 rb.Push(result); 2030 rb.Push(result);
@@ -2082,7 +2035,7 @@ void IHidServer::EnablePalmaStep(HLERequestContext& ctx) {
2082 struct Parameters { 2035 struct Parameters {
2083 bool is_enabled; 2036 bool is_enabled;
2084 INSERT_PADDING_WORDS_NOINIT(1); 2037 INSERT_PADDING_WORDS_NOINIT(1);
2085 Controller_Palma::PalmaConnectionHandle connection_handle; 2038 Palma::PalmaConnectionHandle connection_handle;
2086 }; 2039 };
2087 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); 2040 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2088 2041
@@ -2091,9 +2044,9 @@ void IHidServer::EnablePalmaStep(HLERequestContext& ctx) {
2091 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, is_enabled={}", 2044 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, is_enabled={}",
2092 parameters.connection_handle.npad_id, parameters.is_enabled); 2045 parameters.connection_handle.npad_id, parameters.is_enabled);
2093 2046
2094 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 2047 auto controller = GetResourceManager()->GetPalma();
2095 const auto result = 2048 const auto result =
2096 controller.EnablePalmaStep(parameters.connection_handle, parameters.is_enabled); 2049 controller->EnablePalmaStep(parameters.connection_handle, parameters.is_enabled);
2097 2050
2098 IPC::ResponseBuilder rb{ctx, 2}; 2051 IPC::ResponseBuilder rb{ctx, 2};
2099 rb.Push(result); 2052 rb.Push(result);
@@ -2101,12 +2054,12 @@ void IHidServer::EnablePalmaStep(HLERequestContext& ctx) {
2101 2054
2102void IHidServer::ResetPalmaStep(HLERequestContext& ctx) { 2055void IHidServer::ResetPalmaStep(HLERequestContext& ctx) {
2103 IPC::RequestParser rp{ctx}; 2056 IPC::RequestParser rp{ctx};
2104 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2057 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2105 2058
2106 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 2059 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2107 2060
2108 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma); 2061 auto controller = GetResourceManager()->GetPalma();
2109 const auto result = controller.ResetPalmaStep(connection_handle); 2062 const auto result = controller->ResetPalmaStep(connection_handle);
2110 2063
2111 IPC::ResponseBuilder rb{ctx, 2}; 2064 IPC::ResponseBuilder rb{ctx, 2};
2112 rb.Push(result); 2065 rb.Push(result);
@@ -2128,13 +2081,11 @@ void IHidServer::WritePalmaApplicationSection(HLERequestContext& ctx) {
2128 2081
2129void IHidServer::ReadPalmaUniqueCode(HLERequestContext& ctx) { 2082void IHidServer::ReadPalmaUniqueCode(HLERequestContext& ctx) {
2130 IPC::RequestParser rp{ctx}; 2083 IPC::RequestParser rp{ctx};
2131 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2084 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2132 2085
2133 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 2086 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2134 2087
2135 GetResourceManager() 2088 GetResourceManager()->GetPalma()->ReadPalmaUniqueCode(connection_handle);
2136 ->GetController<Controller_Palma>(HidController::Palma)
2137 .ReadPalmaUniqueCode(connection_handle);
2138 2089
2139 IPC::ResponseBuilder rb{ctx, 2}; 2090 IPC::ResponseBuilder rb{ctx, 2};
2140 rb.Push(ResultSuccess); 2091 rb.Push(ResultSuccess);
@@ -2142,13 +2093,11 @@ void IHidServer::ReadPalmaUniqueCode(HLERequestContext& ctx) {
2142 2093
2143void IHidServer::SetPalmaUniqueCodeInvalid(HLERequestContext& ctx) { 2094void IHidServer::SetPalmaUniqueCodeInvalid(HLERequestContext& ctx) {
2144 IPC::RequestParser rp{ctx}; 2095 IPC::RequestParser rp{ctx};
2145 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2096 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2146 2097
2147 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 2098 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2148 2099
2149 GetResourceManager() 2100 GetResourceManager()->GetPalma()->SetPalmaUniqueCodeInvalid(connection_handle);
2150 ->GetController<Controller_Palma>(HidController::Palma)
2151 .SetPalmaUniqueCodeInvalid(connection_handle);
2152 2101
2153 IPC::ResponseBuilder rb{ctx, 2}; 2102 IPC::ResponseBuilder rb{ctx, 2};
2154 rb.Push(ResultSuccess); 2103 rb.Push(ResultSuccess);
@@ -2163,7 +2112,7 @@ void IHidServer::WritePalmaActivityEntry(HLERequestContext& ctx) {
2163 2112
2164void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) { 2113void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) {
2165 IPC::RequestParser rp{ctx}; 2114 IPC::RequestParser rp{ctx};
2166 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2115 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2167 const auto unknown{rp.Pop<u64>()}; 2116 const auto unknown{rp.Pop<u64>()};
2168 2117
2169 [[maybe_unused]] const auto buffer = ctx.ReadBuffer(); 2118 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
@@ -2171,9 +2120,7 @@ void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) {
2171 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}", 2120 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
2172 connection_handle.npad_id, unknown); 2121 connection_handle.npad_id, unknown);
2173 2122
2174 GetResourceManager() 2123 GetResourceManager()->GetPalma()->WritePalmaRgbLedPatternEntry(connection_handle, unknown);
2175 ->GetController<Controller_Palma>(HidController::Palma)
2176 .WritePalmaRgbLedPatternEntry(connection_handle, unknown);
2177 2124
2178 IPC::ResponseBuilder rb{ctx, 2}; 2125 IPC::ResponseBuilder rb{ctx, 2};
2179 rb.Push(ResultSuccess); 2126 rb.Push(ResultSuccess);
@@ -2181,8 +2128,8 @@ void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) {
2181 2128
2182void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) { 2129void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
2183 IPC::RequestParser rp{ctx}; 2130 IPC::RequestParser rp{ctx};
2184 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2131 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2185 const auto wave_set{rp.PopEnum<Controller_Palma::PalmaWaveSet>()}; 2132 const auto wave_set{rp.PopEnum<Palma::PalmaWaveSet>()};
2186 const auto unknown{rp.Pop<u64>()}; 2133 const auto unknown{rp.Pop<u64>()};
2187 const auto t_mem_size{rp.Pop<u64>()}; 2134 const auto t_mem_size{rp.Pop<u64>()};
2188 const auto t_mem_handle{ctx.GetCopyHandle(0)}; 2135 const auto t_mem_handle{ctx.GetCopyHandle(0)};
@@ -2207,9 +2154,8 @@ void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
2207 "t_mem_handle=0x{:08X}, t_mem_size={}, size={}", 2154 "t_mem_handle=0x{:08X}, t_mem_size={}, size={}",
2208 connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size); 2155 connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size);
2209 2156
2210 GetResourceManager() 2157 GetResourceManager()->GetPalma()->WritePalmaWaveEntry(connection_handle, wave_set,
2211 ->GetController<Controller_Palma>(HidController::Palma) 2158 t_mem->GetSourceAddress(), t_mem_size);
2212 .WritePalmaWaveEntry(connection_handle, wave_set, t_mem->GetSourceAddress(), t_mem_size);
2213 2159
2214 IPC::ResponseBuilder rb{ctx, 2}; 2160 IPC::ResponseBuilder rb{ctx, 2};
2215 rb.Push(ResultSuccess); 2161 rb.Push(ResultSuccess);
@@ -2220,7 +2166,7 @@ void IHidServer::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
2220 struct Parameters { 2166 struct Parameters {
2221 s32 database_id_version; 2167 s32 database_id_version;
2222 INSERT_PADDING_WORDS_NOINIT(1); 2168 INSERT_PADDING_WORDS_NOINIT(1);
2223 Controller_Palma::PalmaConnectionHandle connection_handle; 2169 Palma::PalmaConnectionHandle connection_handle;
2224 }; 2170 };
2225 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); 2171 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2226 2172
@@ -2229,10 +2175,8 @@ void IHidServer::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
2229 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, database_id_version={}", 2175 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, database_id_version={}",
2230 parameters.connection_handle.npad_id, parameters.database_id_version); 2176 parameters.connection_handle.npad_id, parameters.database_id_version);
2231 2177
2232 GetResourceManager() 2178 GetResourceManager()->GetPalma()->SetPalmaDataBaseIdentificationVersion(
2233 ->GetController<Controller_Palma>(HidController::Palma) 2179 parameters.connection_handle, parameters.database_id_version);
2234 .SetPalmaDataBaseIdentificationVersion(parameters.connection_handle,
2235 parameters.database_id_version);
2236 2180
2237 IPC::ResponseBuilder rb{ctx, 2}; 2181 IPC::ResponseBuilder rb{ctx, 2};
2238 rb.Push(ResultSuccess); 2182 rb.Push(ResultSuccess);
@@ -2240,13 +2184,11 @@ void IHidServer::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
2240 2184
2241void IHidServer::GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) { 2185void IHidServer::GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
2242 IPC::RequestParser rp{ctx}; 2186 IPC::RequestParser rp{ctx};
2243 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2187 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2244 2188
2245 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 2189 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2246 2190
2247 GetResourceManager() 2191 GetResourceManager()->GetPalma()->GetPalmaDataBaseIdentificationVersion(connection_handle);
2248 ->GetController<Controller_Palma>(HidController::Palma)
2249 .GetPalmaDataBaseIdentificationVersion(connection_handle);
2250 2192
2251 IPC::ResponseBuilder rb{ctx, 2}; 2193 IPC::ResponseBuilder rb{ctx, 2};
2252 rb.Push(ResultSuccess); 2194 rb.Push(ResultSuccess);
@@ -2261,13 +2203,12 @@ void IHidServer::SuspendPalmaFeature(HLERequestContext& ctx) {
2261 2203
2262void IHidServer::GetPalmaOperationResult(HLERequestContext& ctx) { 2204void IHidServer::GetPalmaOperationResult(HLERequestContext& ctx) {
2263 IPC::RequestParser rp{ctx}; 2205 IPC::RequestParser rp{ctx};
2264 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2206 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2265 2207
2266 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 2208 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2267 2209
2268 const auto result = GetResourceManager() 2210 const auto result =
2269 ->GetController<Controller_Palma>(HidController::Palma) 2211 GetResourceManager()->GetPalma()->GetPalmaOperationResult(connection_handle);
2270 .GetPalmaOperationResult(connection_handle);
2271 2212
2272 IPC::ResponseBuilder rb{ctx, 2}; 2213 IPC::ResponseBuilder rb{ctx, 2};
2273 rb.Push(result); 2214 rb.Push(result);
@@ -2302,9 +2243,7 @@ void IHidServer::SetIsPalmaAllConnectable(HLERequestContext& ctx) {
2302 "(STUBBED) called, is_palma_all_connectable={},applet_resource_user_id={}", 2243 "(STUBBED) called, is_palma_all_connectable={},applet_resource_user_id={}",
2303 parameters.is_palma_all_connectable, parameters.applet_resource_user_id); 2244 parameters.is_palma_all_connectable, parameters.applet_resource_user_id);
2304 2245
2305 GetResourceManager() 2246 GetResourceManager()->GetPalma()->SetIsPalmaAllConnectable(parameters.is_palma_all_connectable);
2306 ->GetController<Controller_Palma>(HidController::Palma)
2307 .SetIsPalmaAllConnectable(parameters.is_palma_all_connectable);
2308 2247
2309 IPC::ResponseBuilder rb{ctx, 2}; 2248 IPC::ResponseBuilder rb{ctx, 2};
2310 rb.Push(ResultSuccess); 2249 rb.Push(ResultSuccess);
@@ -2319,13 +2258,11 @@ void IHidServer::SetIsPalmaPairedConnectable(HLERequestContext& ctx) {
2319 2258
2320void IHidServer::PairPalma(HLERequestContext& ctx) { 2259void IHidServer::PairPalma(HLERequestContext& ctx) {
2321 IPC::RequestParser rp{ctx}; 2260 IPC::RequestParser rp{ctx};
2322 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()}; 2261 const auto connection_handle{rp.PopRaw<Palma::PalmaConnectionHandle>()};
2323 2262
2324 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id); 2263 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2325 2264
2326 GetResourceManager() 2265 GetResourceManager()->GetPalma()->PairPalma(connection_handle);
2327 ->GetController<Controller_Palma>(HidController::Palma)
2328 .PairPalma(connection_handle);
2329 2266
2330 IPC::ResponseBuilder rb{ctx, 2}; 2267 IPC::ResponseBuilder rb{ctx, 2};
2331 rb.Push(ResultSuccess); 2268 rb.Push(ResultSuccess);
@@ -2337,9 +2274,7 @@ void IHidServer::SetPalmaBoostMode(HLERequestContext& ctx) {
2337 2274
2338 LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode); 2275 LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode);
2339 2276
2340 GetResourceManager() 2277 GetResourceManager()->GetPalma()->SetPalmaBoostMode(palma_boost_mode);
2341 ->GetController<Controller_Palma>(HidController::Palma)
2342 .SetPalmaBoostMode(palma_boost_mode);
2343 2278
2344 IPC::ResponseBuilder rb{ctx, 2}; 2279 IPC::ResponseBuilder rb{ctx, 2};
2345 rb.Push(ResultSuccess); 2280 rb.Push(ResultSuccess);
@@ -2376,11 +2311,9 @@ void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
2376void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { 2311void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) {
2377 IPC::RequestParser rp{ctx}; 2312 IPC::RequestParser rp{ctx};
2378 const auto applet_resource_user_id{rp.Pop<u64>()}; 2313 const auto applet_resource_user_id{rp.Pop<u64>()};
2379 const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()}; 2314 const auto communication_mode{rp.PopEnum<NPad::NpadCommunicationMode>()};
2380 2315
2381 GetResourceManager() 2316 GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode);
2382 ->GetController<Controller_NPad>(HidController::NPad)
2383 .SetNpadCommunicationMode(communication_mode);
2384 2317
2385 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}", 2318 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}",
2386 applet_resource_user_id, communication_mode); 2319 applet_resource_user_id, communication_mode);
@@ -2396,9 +2329,7 @@ void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) {
2396 2329
2397 IPC::ResponseBuilder rb{ctx, 4}; 2330 IPC::ResponseBuilder rb{ctx, 4};
2398 rb.Push(ResultSuccess); 2331 rb.Push(ResultSuccess);
2399 rb.PushEnum(GetResourceManager() 2332 rb.PushEnum(GetResourceManager()->GetNpad()->GetNpadCommunicationMode());
2400 ->GetController<Controller_NPad>(HidController::NPad)
2401 .GetNpadCommunicationMode());
2402} 2333}
2403 2334
2404void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) { 2335void 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
16 resource_manager{resource} { 16 resource_manager{resource} {
17 // clang-format off 17 // clang-format off
18 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
19 {31, nullptr, "SendKeyboardLockKeyEvent"}, 19 {31, nullptr, "SendKeyboardLockKeyEvent"},
20 {101, nullptr, "AcquireHomeButtonEventHandle"}, 20 {101, nullptr, "AcquireHomeButtonEventHandle"},
21 {111, nullptr, "ActivateHomeButton"}, 21 {111, nullptr, "ActivateHomeButton"},
22 {121, nullptr, "AcquireSleepButtonEventHandle"}, 22 {121, nullptr, "AcquireSleepButtonEventHandle"},
23 {131, nullptr, "ActivateSleepButton"}, 23 {131, nullptr, "ActivateSleepButton"},
24 {141, nullptr, "AcquireCaptureButtonEventHandle"}, 24 {141, nullptr, "AcquireCaptureButtonEventHandle"},
25 {151, nullptr, "ActivateCaptureButton"}, 25 {151, nullptr, "ActivateCaptureButton"},
26 {161, nullptr, "GetPlatformConfig"}, 26 {161, nullptr, "GetPlatformConfig"},
27 {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"}, 27 {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
28 {211, nullptr, "GetNpadsWithNfc"}, 28 {211, nullptr, "GetNpadsWithNfc"},
29 {212, nullptr, "AcquireNfcActivateEventHandle"}, 29 {212, nullptr, "AcquireNfcActivateEventHandle"},
30 {213, nullptr, "ActivateNfc"}, 30 {213, nullptr, "ActivateNfc"},
31 {214, nullptr, "GetXcdHandleForNpadWithNfc"}, 31 {214, nullptr, "GetXcdHandleForNpadWithNfc"},
32 {215, nullptr, "IsNfcActivated"}, 32 {215, nullptr, "IsNfcActivated"},
33 {230, nullptr, "AcquireIrSensorEventHandle"}, 33 {230, nullptr, "AcquireIrSensorEventHandle"},
34 {231, nullptr, "ActivateIrSensor"}, 34 {231, nullptr, "ActivateIrSensor"},
35 {232, nullptr, "GetIrSensorState"}, 35 {232, nullptr, "GetIrSensorState"},
36 {233, nullptr, "GetXcdHandleForNpadWithIrSensor"}, 36 {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
37 {301, nullptr, "ActivateNpadSystem"}, 37 {301, nullptr, "ActivateNpadSystem"},
38 {303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"}, 38 {303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
39 {304, &IHidSystemServer::EnableAssigningSingleOnSlSrPress, "EnableAssigningSingleOnSlSrPress"}, 39 {304, &IHidSystemServer::EnableAssigningSingleOnSlSrPress, "EnableAssigningSingleOnSlSrPress"},
40 {305, &IHidSystemServer::DisableAssigningSingleOnSlSrPress, "DisableAssigningSingleOnSlSrPress"}, 40 {305, &IHidSystemServer::DisableAssigningSingleOnSlSrPress, "DisableAssigningSingleOnSlSrPress"},
41 {306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"}, 41 {306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"},
42 {307, nullptr, "GetNpadSystemExtStyle"}, 42 {307, nullptr, "GetNpadSystemExtStyle"},
43 {308, &IHidSystemServer::ApplyNpadSystemCommonPolicyFull, "ApplyNpadSystemCommonPolicyFull"}, 43 {308, &IHidSystemServer::ApplyNpadSystemCommonPolicyFull, "ApplyNpadSystemCommonPolicyFull"},
44 {309, &IHidSystemServer::GetNpadFullKeyGripColor, "GetNpadFullKeyGripColor"}, 44 {309, &IHidSystemServer::GetNpadFullKeyGripColor, "GetNpadFullKeyGripColor"},
45 {310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"}, 45 {310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"},
46 {311, nullptr, "SetNpadPlayerLedBlinkingDevice"}, 46 {311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
47 {312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"}, 47 {312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"},
48 {313, nullptr, "GetNpadCaptureButtonAssignment"}, 48 {313, nullptr, "GetNpadCaptureButtonAssignment"},
49 {314, nullptr, "GetAppletFooterUiType"}, 49 {314, nullptr, "GetAppletFooterUiType"},
50 {315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"}, 50 {315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"},
51 {316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"}, 51 {316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"},
52 {317, &IHidSystemServer::GetNpadLeftRightInterfaceType, "GetNpadLeftRightInterfaceType"}, 52 {317, &IHidSystemServer::GetNpadLeftRightInterfaceType, "GetNpadLeftRightInterfaceType"},
53 {318, &IHidSystemServer::HasBattery, "HasBattery"}, 53 {318, &IHidSystemServer::HasBattery, "HasBattery"},
54 {319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"}, 54 {319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"},
55 {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"}, 55 {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
56 {322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"}, 56 {322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"},
57 {323, nullptr, "GetXcdHandleForNpadWithIrSensor"}, 57 {323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
58 {324, nullptr, "GetUniquePadButtonSet"}, 58 {324, nullptr, "GetUniquePadButtonSet"},
59 {325, nullptr, "GetUniquePadColor"}, 59 {325, nullptr, "GetUniquePadColor"},
60 {326, nullptr, "GetUniquePadAppletDetailedUiType"}, 60 {326, nullptr, "GetUniquePadAppletDetailedUiType"},
61 {327, nullptr, "GetAbstractedPadIdDataFromNpad"}, 61 {327, nullptr, "GetAbstractedPadIdDataFromNpad"},
62 {328, nullptr, "AttachAbstractedPadToNpad"}, 62 {328, nullptr, "AttachAbstractedPadToNpad"},
63 {329, nullptr, "DetachAbstractedPadAll"}, 63 {329, nullptr, "DetachAbstractedPadAll"},
64 {330, nullptr, "CheckAbstractedPadConnection"}, 64 {330, nullptr, "CheckAbstractedPadConnection"},
65 {500, nullptr, "SetAppletResourceUserId"}, 65 {500, nullptr, "SetAppletResourceUserId"},
66 {501, nullptr, "RegisterAppletResourceUserId"}, 66 {501, nullptr, "RegisterAppletResourceUserId"},
67 {502, nullptr, "UnregisterAppletResourceUserId"}, 67 {502, nullptr, "UnregisterAppletResourceUserId"},
68 {503, nullptr, "EnableAppletToGetInput"}, 68 {503, nullptr, "EnableAppletToGetInput"},
69 {504, nullptr, "SetAruidValidForVibration"}, 69 {504, nullptr, "SetAruidValidForVibration"},
70 {505, nullptr, "EnableAppletToGetSixAxisSensor"}, 70 {505, nullptr, "EnableAppletToGetSixAxisSensor"},
71 {506, nullptr, "EnableAppletToGetPadInput"}, 71 {506, nullptr, "EnableAppletToGetPadInput"},
72 {507, nullptr, "EnableAppletToGetTouchScreen"}, 72 {507, nullptr, "EnableAppletToGetTouchScreen"},
73 {510, nullptr, "SetVibrationMasterVolume"}, 73 {510, nullptr, "SetVibrationMasterVolume"},
74 {511, nullptr, "GetVibrationMasterVolume"}, 74 {511, nullptr, "GetVibrationMasterVolume"},
75 {512, nullptr, "BeginPermitVibrationSession"}, 75 {512, nullptr, "BeginPermitVibrationSession"},
76 {513, nullptr, "EndPermitVibrationSession"}, 76 {513, nullptr, "EndPermitVibrationSession"},
77 {514, nullptr, "Unknown514"}, 77 {514, nullptr, "Unknown514"},
78 {520, nullptr, "EnableHandheldHids"}, 78 {520, nullptr, "EnableHandheldHids"},
79 {521, nullptr, "DisableHandheldHids"}, 79 {521, nullptr, "DisableHandheldHids"},
80 {522, nullptr, "SetJoyConRailEnabled"}, 80 {522, nullptr, "SetJoyConRailEnabled"},
81 {523, nullptr, "IsJoyConRailEnabled"}, 81 {523, nullptr, "IsJoyConRailEnabled"},
82 {524, nullptr, "IsHandheldHidsEnabled"}, 82 {524, nullptr, "IsHandheldHidsEnabled"},
83 {525, nullptr, "IsJoyConAttachedOnAllRail"}, 83 {525, nullptr, "IsJoyConAttachedOnAllRail"},
84 {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, 84 {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
85 {541, nullptr, "GetPlayReportControllerUsages"}, 85 {541, nullptr, "GetPlayReportControllerUsages"},
86 {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, 86 {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
87 {543, nullptr, "GetRegisteredDevicesOld"}, 87 {543, nullptr, "GetRegisteredDevicesOld"},
88 {544, &IHidSystemServer::AcquireConnectionTriggerTimeoutEvent, "AcquireConnectionTriggerTimeoutEvent"}, 88 {544, &IHidSystemServer::AcquireConnectionTriggerTimeoutEvent, "AcquireConnectionTriggerTimeoutEvent"},
89 {545, nullptr, "SendConnectionTrigger"}, 89 {545, nullptr, "SendConnectionTrigger"},
90 {546, &IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport, "AcquireDeviceRegisteredEventForControllerSupport"}, 90 {546, &IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport, "AcquireDeviceRegisteredEventForControllerSupport"},
91 {547, nullptr, "GetAllowedBluetoothLinksCount"}, 91 {547, nullptr, "GetAllowedBluetoothLinksCount"},
92 {548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"}, 92 {548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
93 {549, nullptr, "GetConnectableRegisteredDevices"}, 93 {549, nullptr, "GetConnectableRegisteredDevices"},
94 {700, nullptr, "ActivateUniquePad"}, 94 {700, nullptr, "ActivateUniquePad"},
95 {702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"}, 95 {702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
96 {703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"}, 96 {703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
97 {751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"}, 97 {751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
98 {800, nullptr, "ListSixAxisSensorHandles"}, 98 {800, nullptr, "ListSixAxisSensorHandles"},
99 {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"}, 99 {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
100 {802, nullptr, "ResetSixAxisSensorCalibrationValues"}, 100 {802, nullptr, "ResetSixAxisSensorCalibrationValues"},
101 {803, nullptr, "StartSixAxisSensorUserCalibration"}, 101 {803, nullptr, "StartSixAxisSensorUserCalibration"},
102 {804, nullptr, "CancelSixAxisSensorUserCalibration"}, 102 {804, nullptr, "CancelSixAxisSensorUserCalibration"},
103 {805, nullptr, "GetUniquePadBluetoothAddress"}, 103 {805, nullptr, "GetUniquePadBluetoothAddress"},
104 {806, nullptr, "DisconnectUniquePad"}, 104 {806, nullptr, "DisconnectUniquePad"},
105 {807, nullptr, "GetUniquePadType"}, 105 {807, nullptr, "GetUniquePadType"},
106 {808, nullptr, "GetUniquePadInterface"}, 106 {808, nullptr, "GetUniquePadInterface"},
107 {809, nullptr, "GetUniquePadSerialNumber"}, 107 {809, nullptr, "GetUniquePadSerialNumber"},
108 {810, nullptr, "GetUniquePadControllerNumber"}, 108 {810, nullptr, "GetUniquePadControllerNumber"},
109 {811, nullptr, "GetSixAxisSensorUserCalibrationStage"}, 109 {811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
110 {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"}, 110 {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
111 {821, nullptr, "StartAnalogStickManualCalibration"}, 111 {821, nullptr, "StartAnalogStickManualCalibration"},
112 {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"}, 112 {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
113 {823, nullptr, "CancelAnalogStickManualCalibration"}, 113 {823, nullptr, "CancelAnalogStickManualCalibration"},
114 {824, nullptr, "ResetAnalogStickManualCalibration"}, 114 {824, nullptr, "ResetAnalogStickManualCalibration"},
115 {825, nullptr, "GetAnalogStickState"}, 115 {825, nullptr, "GetAnalogStickState"},
116 {826, nullptr, "GetAnalogStickManualCalibrationStage"}, 116 {826, nullptr, "GetAnalogStickManualCalibrationStage"},
117 {827, nullptr, "IsAnalogStickButtonPressed"}, 117 {827, nullptr, "IsAnalogStickButtonPressed"},
118 {828, nullptr, "IsAnalogStickInReleasePosition"}, 118 {828, nullptr, "IsAnalogStickInReleasePosition"},
119 {829, nullptr, "IsAnalogStickInCircumference"}, 119 {829, nullptr, "IsAnalogStickInCircumference"},
120 {830, nullptr, "SetNotificationLedPattern"}, 120 {830, nullptr, "SetNotificationLedPattern"},
121 {831, nullptr, "SetNotificationLedPatternWithTimeout"}, 121 {831, nullptr, "SetNotificationLedPatternWithTimeout"},
122 {832, nullptr, "PrepareHidsForNotificationWake"}, 122 {832, nullptr, "PrepareHidsForNotificationWake"},
123 {850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"}, 123 {850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
124 {851, nullptr, "EnableUsbFullKeyController"}, 124 {851, nullptr, "EnableUsbFullKeyController"},
125 {852, nullptr, "IsUsbConnected"}, 125 {852, nullptr, "IsUsbConnected"},
126 {870, &IHidSystemServer::IsHandheldButtonPressedOnConsoleMode, "IsHandheldButtonPressedOnConsoleMode"}, 126 {870, &IHidSystemServer::IsHandheldButtonPressedOnConsoleMode, "IsHandheldButtonPressedOnConsoleMode"},
127 {900, nullptr, "ActivateInputDetector"}, 127 {900, nullptr, "ActivateInputDetector"},
128 {901, nullptr, "NotifyInputDetector"}, 128 {901, nullptr, "NotifyInputDetector"},
129 {1000, &IHidSystemServer::InitializeFirmwareUpdate, "InitializeFirmwareUpdate"}, 129 {1000, &IHidSystemServer::InitializeFirmwareUpdate, "InitializeFirmwareUpdate"},
130 {1001, nullptr, "GetFirmwareVersion"}, 130 {1001, nullptr, "GetFirmwareVersion"},
131 {1002, nullptr, "GetAvailableFirmwareVersion"}, 131 {1002, nullptr, "GetAvailableFirmwareVersion"},
132 {1003, nullptr, "IsFirmwareUpdateAvailable"}, 132 {1003, nullptr, "IsFirmwareUpdateAvailable"},
133 {1004, nullptr, "CheckFirmwareUpdateRequired"}, 133 {1004, nullptr, "CheckFirmwareUpdateRequired"},
134 {1005, nullptr, "StartFirmwareUpdate"}, 134 {1005, nullptr, "StartFirmwareUpdate"},
135 {1006, nullptr, "AbortFirmwareUpdate"}, 135 {1006, nullptr, "AbortFirmwareUpdate"},
136 {1007, nullptr, "GetFirmwareUpdateState"}, 136 {1007, nullptr, "GetFirmwareUpdateState"},
137 {1008, nullptr, "ActivateAudioControl"}, 137 {1008, nullptr, "ActivateAudioControl"},
138 {1009, nullptr, "AcquireAudioControlEventHandle"}, 138 {1009, nullptr, "AcquireAudioControlEventHandle"},
139 {1010, nullptr, "GetAudioControlStates"}, 139 {1010, nullptr, "GetAudioControlStates"},
140 {1011, nullptr, "DeactivateAudioControl"}, 140 {1011, nullptr, "DeactivateAudioControl"},
141 {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"}, 141 {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
142 {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"}, 142 {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
143 {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"}, 143 {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
144 {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"}, 144 {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
145 {1100, nullptr, "GetHidbusSystemServiceObject"}, 145 {1100, nullptr, "GetHidbusSystemServiceObject"},
146 {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"}, 146 {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
147 {1130, nullptr, "InitializeUsbFirmwareUpdate"}, 147 {1130, nullptr, "InitializeUsbFirmwareUpdate"},
148 {1131, nullptr, "FinalizeUsbFirmwareUpdate"}, 148 {1131, nullptr, "FinalizeUsbFirmwareUpdate"},
149 {1132, nullptr, "CheckUsbFirmwareUpdateRequired"}, 149 {1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
150 {1133, nullptr, "StartUsbFirmwareUpdate"}, 150 {1133, nullptr, "StartUsbFirmwareUpdate"},
151 {1134, nullptr, "GetUsbFirmwareUpdateState"}, 151 {1134, nullptr, "GetUsbFirmwareUpdateState"},
152 {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"}, 152 {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"},
153 {1150, nullptr, "SetTouchScreenMagnification"}, 153 {1150, nullptr, "SetTouchScreenMagnification"},
154 {1151, nullptr, "GetTouchScreenFirmwareVersion"}, 154 {1151, nullptr, "GetTouchScreenFirmwareVersion"},
155 {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, 155 {1152, nullptr, "SetTouchScreenDefaultConfiguration"},
156 {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, 156 {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
157 {1154, nullptr, "IsFirmwareAvailableForNotification"}, 157 {1154, nullptr, "IsFirmwareAvailableForNotification"},
158 {1155, nullptr, "SetForceHandheldStyleVibration"}, 158 {1155, nullptr, "SetForceHandheldStyleVibration"},
159 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, 159 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
160 {1157, nullptr, "CancelConnectionTrigger"}, 160 {1157, nullptr, "CancelConnectionTrigger"},
161 {1200, nullptr, "IsButtonConfigSupported"}, 161 {1200, nullptr, "IsButtonConfigSupported"},
162 {1201, nullptr, "IsButtonConfigEmbeddedSupported"}, 162 {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
163 {1202, nullptr, "DeleteButtonConfig"}, 163 {1202, nullptr, "DeleteButtonConfig"},
164 {1203, nullptr, "DeleteButtonConfigEmbedded"}, 164 {1203, nullptr, "DeleteButtonConfigEmbedded"},
165 {1204, nullptr, "SetButtonConfigEnabled"}, 165 {1204, nullptr, "SetButtonConfigEnabled"},
166 {1205, nullptr, "SetButtonConfigEmbeddedEnabled"}, 166 {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
167 {1206, nullptr, "IsButtonConfigEnabled"}, 167 {1206, nullptr, "IsButtonConfigEnabled"},
168 {1207, nullptr, "IsButtonConfigEmbeddedEnabled"}, 168 {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
169 {1208, nullptr, "SetButtonConfigEmbedded"}, 169 {1208, nullptr, "SetButtonConfigEmbedded"},
170 {1209, nullptr, "SetButtonConfigFull"}, 170 {1209, nullptr, "SetButtonConfigFull"},
171 {1210, nullptr, "SetButtonConfigLeft"}, 171 {1210, nullptr, "SetButtonConfigLeft"},
172 {1211, nullptr, "SetButtonConfigRight"}, 172 {1211, nullptr, "SetButtonConfigRight"},
173 {1212, nullptr, "GetButtonConfigEmbedded"}, 173 {1212, nullptr, "GetButtonConfigEmbedded"},
174 {1213, nullptr, "GetButtonConfigFull"}, 174 {1213, nullptr, "GetButtonConfigFull"},
175 {1214, nullptr, "GetButtonConfigLeft"}, 175 {1214, nullptr, "GetButtonConfigLeft"},
176 {1215, nullptr, "GetButtonConfigRight"}, 176 {1215, nullptr, "GetButtonConfigRight"},
177 {1250, nullptr, "IsCustomButtonConfigSupported"}, 177 {1250, nullptr, "IsCustomButtonConfigSupported"},
178 {1251, nullptr, "IsDefaultButtonConfigEmbedded"}, 178 {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
179 {1252, nullptr, "IsDefaultButtonConfigFull"}, 179 {1252, nullptr, "IsDefaultButtonConfigFull"},
180 {1253, nullptr, "IsDefaultButtonConfigLeft"}, 180 {1253, nullptr, "IsDefaultButtonConfigLeft"},
181 {1254, nullptr, "IsDefaultButtonConfigRight"}, 181 {1254, nullptr, "IsDefaultButtonConfigRight"},
182 {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"}, 182 {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
183 {1256, nullptr, "IsButtonConfigStorageFullEmpty"}, 183 {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
184 {1257, nullptr, "IsButtonConfigStorageLeftEmpty"}, 184 {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
185 {1258, nullptr, "IsButtonConfigStorageRightEmpty"}, 185 {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
186 {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"}, 186 {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
187 {1260, nullptr, "GetButtonConfigStorageFullDeprecated"}, 187 {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
188 {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"}, 188 {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
189 {1262, nullptr, "GetButtonConfigStorageRightDeprecated"}, 189 {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
190 {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"}, 190 {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
191 {1264, nullptr, "SetButtonConfigStorageFullDeprecated"}, 191 {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
192 {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"}, 192 {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
193 {1266, nullptr, "SetButtonConfigStorageRightDeprecated"}, 193 {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
194 {1267, nullptr, "DeleteButtonConfigStorageEmbedded"}, 194 {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
195 {1268, nullptr, "DeleteButtonConfigStorageFull"}, 195 {1268, nullptr, "DeleteButtonConfigStorageFull"},
196 {1269, nullptr, "DeleteButtonConfigStorageLeft"}, 196 {1269, nullptr, "DeleteButtonConfigStorageLeft"},
197 {1270, nullptr, "DeleteButtonConfigStorageRight"}, 197 {1270, nullptr, "DeleteButtonConfigStorageRight"},
198 {1271, nullptr, "IsUsingCustomButtonConfig"}, 198 {1271, nullptr, "IsUsingCustomButtonConfig"},
199 {1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, 199 {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
200 {1273, nullptr, "SetAllCustomButtonConfigEnabled"}, 200 {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
201 {1274, nullptr, "SetDefaultButtonConfig"}, 201 {1274, nullptr, "SetDefaultButtonConfig"},
202 {1275, nullptr, "SetAllDefaultButtonConfig"}, 202 {1275, nullptr, "SetAllDefaultButtonConfig"},
203 {1276, nullptr, "SetHidButtonConfigEmbedded"}, 203 {1276, nullptr, "SetHidButtonConfigEmbedded"},
204 {1277, nullptr, "SetHidButtonConfigFull"}, 204 {1277, nullptr, "SetHidButtonConfigFull"},
205 {1278, nullptr, "SetHidButtonConfigLeft"}, 205 {1278, nullptr, "SetHidButtonConfigLeft"},
206 {1279, nullptr, "SetHidButtonConfigRight"}, 206 {1279, nullptr, "SetHidButtonConfigRight"},
207 {1280, nullptr, "GetHidButtonConfigEmbedded"}, 207 {1280, nullptr, "GetHidButtonConfigEmbedded"},
208 {1281, nullptr, "GetHidButtonConfigFull"}, 208 {1281, nullptr, "GetHidButtonConfigFull"},
209 {1282, nullptr, "GetHidButtonConfigLeft"}, 209 {1282, nullptr, "GetHidButtonConfigLeft"},
210 {1283, nullptr, "GetHidButtonConfigRight"}, 210 {1283, nullptr, "GetHidButtonConfigRight"},
211 {1284, nullptr, "GetButtonConfigStorageEmbedded"}, 211 {1284, nullptr, "GetButtonConfigStorageEmbedded"},
212 {1285, nullptr, "GetButtonConfigStorageFull"}, 212 {1285, nullptr, "GetButtonConfigStorageFull"},
213 {1286, nullptr, "GetButtonConfigStorageLeft"}, 213 {1286, nullptr, "GetButtonConfigStorageLeft"},
214 {1287, nullptr, "GetButtonConfigStorageRight"}, 214 {1287, nullptr, "GetButtonConfigStorageRight"},
215 {1288, nullptr, "SetButtonConfigStorageEmbedded"}, 215 {1288, nullptr, "SetButtonConfigStorageEmbedded"},
216 {1289, nullptr, "SetButtonConfigStorageFull"}, 216 {1289, nullptr, "SetButtonConfigStorageFull"},
217 {1290, nullptr, "DeleteButtonConfigStorageRight"}, 217 {1290, nullptr, "DeleteButtonConfigStorageRight"},
218 {1291, nullptr, "DeleteButtonConfigStorageRight"}, 218 {1291, nullptr, "DeleteButtonConfigStorageRight"},
219 }; 219 };
220 // clang-format on 220 // clang-format on
221 221
@@ -240,9 +240,7 @@ IHidSystemServer::~IHidSystemServer() {
240void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) { 240void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
241 LOG_WARNING(Service_HID, "called"); 241 LOG_WARNING(Service_HID, "called");
242 242
243 GetResourceManager() 243 GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy();
244 ->GetController<Controller_NPad>(HidController::NPad)
245 .ApplyNpadSystemCommonPolicy();
246 244
247 IPC::ResponseBuilder rb{ctx, 2}; 245 IPC::ResponseBuilder rb{ctx, 2};
248 rb.Push(ResultSuccess); 246 rb.Push(ResultSuccess);
@@ -273,9 +271,7 @@ void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
273void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) { 271void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
274 LOG_WARNING(Service_HID, "called"); 272 LOG_WARNING(Service_HID, "called");
275 273
276 GetResourceManager() 274 GetResourceManager()->GetNpad()->ApplyNpadSystemCommonPolicy();
277 ->GetController<Controller_NPad>(HidController::NPad)
278 .ApplyNpadSystemCommonPolicy();
279 275
280 IPC::ResponseBuilder rb{ctx, 2}; 276 IPC::ResponseBuilder rb{ctx, 2};
281 rb.Push(ResultSuccess); 277 rb.Push(ResultSuccess);
@@ -304,10 +300,7 @@ void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) {
304 LOG_INFO(Service_HID, "(STUBBED) called"); 300 LOG_INFO(Service_HID, "(STUBBED) called");
305 301
306 Core::HID::NpadStyleSet supported_styleset = 302 Core::HID::NpadStyleSet supported_styleset =
307 GetResourceManager() 303 GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw;
308 ->GetController<Controller_NPad>(HidController::NPad)
309 .GetSupportedStyleSet()
310 .raw;
311 304
312 IPC::ResponseBuilder rb{ctx, 3}; 305 IPC::ResponseBuilder rb{ctx, 3};
313 rb.Push(ResultSuccess); 306 rb.Push(ResultSuccess);
@@ -320,10 +313,7 @@ void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) {
320 LOG_INFO(Service_HID, "(STUBBED) called"); 313 LOG_INFO(Service_HID, "(STUBBED) called");
321 314
322 Core::HID::NpadStyleSet supported_styleset = 315 Core::HID::NpadStyleSet supported_styleset =
323 GetResourceManager() 316 GetResourceManager()->GetNpad()->GetSupportedStyleSet().raw;
324 ->GetController<Controller_NPad>(HidController::NPad)
325 .GetSupportedStyleSet()
326 .raw;
327 317
328 IPC::ResponseBuilder rb{ctx, 3}; 318 IPC::ResponseBuilder rb{ctx, 3};
329 rb.Push(ResultSuccess); 319 rb.Push(ResultSuccess);
@@ -337,10 +327,8 @@ void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
337 LOG_DEBUG(Service_HID, "called, npad_id_type={}", 327 LOG_DEBUG(Service_HID, "called, npad_id_type={}",
338 npad_id_type); // Spams a lot when controller applet is running 328 npad_id_type); // Spams a lot when controller applet is running
339 329
340 const Service::HID::Controller_NPad::AppletDetailedUiType detailed_ui_type = 330 const NPad::AppletDetailedUiType detailed_ui_type =
341 GetResourceManager() 331 GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type);
342 ->GetController<Controller_NPad>(HidController::NPad)
343 .GetAppletDetailedUiType(npad_id_type);
344 332
345 IPC::ResponseBuilder rb{ctx, 3}; 333 IPC::ResponseBuilder rb{ctx, 3};
346 rb.Push(ResultSuccess); 334 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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hid/hid_types.h"
7#include "core/hle/service/hid/errors.h"
8
9namespace Service::HID {
10
11constexpr bool IsNpadIdValid(const Core::HID::NpadIdType npad_id) {
12 switch (npad_id) {
13 case Core::HID::NpadIdType::Player1:
14 case Core::HID::NpadIdType::Player2:
15 case Core::HID::NpadIdType::Player3:
16 case Core::HID::NpadIdType::Player4:
17 case Core::HID::NpadIdType::Player5:
18 case Core::HID::NpadIdType::Player6:
19 case Core::HID::NpadIdType::Player7:
20 case Core::HID::NpadIdType::Player8:
21 case Core::HID::NpadIdType::Other:
22 case Core::HID::NpadIdType::Handheld:
23 return true;
24 default:
25 return false;
26 }
27}
28
29constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& handle) {
30 const auto npad_id = IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id));
31 const bool device_index = handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex;
32
33 if (!npad_id) {
34 return InvalidNpadId;
35 }
36 if (!device_index) {
37 return NpadDeviceIndexOutOfRange;
38 }
39
40 return ResultSuccess;
41}
42
43constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) {
44 switch (handle.npad_type) {
45 case Core::HID::NpadStyleIndex::ProController:
46 case Core::HID::NpadStyleIndex::Handheld:
47 case Core::HID::NpadStyleIndex::JoyconDual:
48 case Core::HID::NpadStyleIndex::JoyconLeft:
49 case Core::HID::NpadStyleIndex::JoyconRight:
50 case Core::HID::NpadStyleIndex::GameCube:
51 case Core::HID::NpadStyleIndex::N64:
52 case Core::HID::NpadStyleIndex::SystemExt:
53 case Core::HID::NpadStyleIndex::System:
54 // These support vibration
55 break;
56 default:
57 return VibrationInvalidStyleIndex;
58 }
59
60 if (!IsNpadIdValid(static_cast<Core::HID::NpadIdType>(handle.npad_id))) {
61 return VibrationInvalidNpadId;
62 }
63
64 if (handle.device_index >= Core::HID::DeviceIndex::MaxDeviceIndex) {
65 return VibrationDeviceIndexOutOfRange;
66 }
67
68 return ResultSuccess;
69}
70
71/// Converts a Core::HID::NpadIdType to an array index.
72constexpr size_t NpadIdTypeToIndex(Core::HID::NpadIdType npad_id_type) {
73 switch (npad_id_type) {
74 case Core::HID::NpadIdType::Player1:
75 return 0;
76 case Core::HID::NpadIdType::Player2:
77 return 1;
78 case Core::HID::NpadIdType::Player3:
79 return 2;
80 case Core::HID::NpadIdType::Player4:
81 return 3;
82 case Core::HID::NpadIdType::Player5:
83 return 4;
84 case Core::HID::NpadIdType::Player6:
85 return 5;
86 case Core::HID::NpadIdType::Player7:
87 return 6;
88 case Core::HID::NpadIdType::Player8:
89 return 7;
90 case Core::HID::NpadIdType::Handheld:
91 return 8;
92 case Core::HID::NpadIdType::Other:
93 return 9;
94 default:
95 return 8;
96 }
97}
98
99/// Converts an array index to a Core::HID::NpadIdType
100constexpr Core::HID::NpadIdType IndexToNpadIdType(size_t index) {
101 switch (index) {
102 case 0:
103 return Core::HID::NpadIdType::Player1;
104 case 1:
105 return Core::HID::NpadIdType::Player2;
106 case 2:
107 return Core::HID::NpadIdType::Player3;
108 case 3:
109 return Core::HID::NpadIdType::Player4;
110 case 4:
111 return Core::HID::NpadIdType::Player5;
112 case 5:
113 return Core::HID::NpadIdType::Player6;
114 case 6:
115 return Core::HID::NpadIdType::Player7;
116 case 7:
117 return Core::HID::NpadIdType::Player8;
118 case 8:
119 return Core::HID::NpadIdType::Handheld;
120 case 9:
121 return Core::HID::NpadIdType::Other;
122 default:
123 return Core::HID::NpadIdType::Invalid;
124 }
125}
126
127constexpr Core::HID::NpadStyleSet GetStylesetByIndex(std::size_t index) {
128 switch (index) {
129 case 0:
130 return Core::HID::NpadStyleSet::Fullkey;
131 case 1:
132 return Core::HID::NpadStyleSet::Handheld;
133 case 2:
134 return Core::HID::NpadStyleSet::JoyDual;
135 case 3:
136 return Core::HID::NpadStyleSet::JoyLeft;
137 case 4:
138 return Core::HID::NpadStyleSet::JoyRight;
139 case 5:
140 return Core::HID::NpadStyleSet::Palma;
141 default:
142 return Core::HID::NpadStyleSet::None;
143 }
144}
145
146} // 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 @@
12#include "core/hle/kernel/k_transfer_memory.h" 12#include "core/hle/kernel/k_transfer_memory.h"
13#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
14#include "core/hle/service/hid/errors.h" 14#include "core/hle/service/hid/errors.h"
15#include "core/hle/service/hid/hid_util.h"
15#include "core/hle/service/hid/irs.h" 16#include "core/hle/service/hid/irs.h"
16#include "core/hle/service/hid/irsensor/clustering_processor.h" 17#include "core/hle/service/hid/irsensor/clustering_processor.h"
17#include "core/hle/service/hid/irsensor/image_transfer_processor.h" 18#include "core/hle/service/hid/irsensor/image_transfer_processor.h"
@@ -320,7 +321,7 @@ void IRS::GetNpadIrCameraHandle(HLERequestContext& ctx) {
320 } 321 }
321 322
322 Core::IrSensor::IrCameraHandle camera_handle{ 323 Core::IrSensor::IrCameraHandle camera_handle{
323 .npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)), 324 .npad_id = static_cast<u8>(HID::NpadIdTypeToIndex(npad_id)),
324 .npad_type = Core::HID::NpadStyleIndex::None, 325 .npad_type = Core::HID::NpadStyleIndex::None,
325 }; 326 };
326 327
@@ -545,7 +546,7 @@ void IRS::ActivateIrsensorWithFunctionLevel(HLERequestContext& ctx) {
545 546
546Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const { 547Result IRS::IsIrCameraHandleValid(const Core::IrSensor::IrCameraHandle& camera_handle) const {
547 if (camera_handle.npad_id > 548 if (camera_handle.npad_id >
548 static_cast<u8>(NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) { 549 static_cast<u8>(HID::NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld))) {
549 return InvalidIrCameraHandle; 550 return InvalidIrCameraHandle;
550 } 551 }
551 if (camera_handle.npad_type != Core::HID::NpadStyleIndex::None) { 552 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 @@
9#include "core/hle/service/hid/resource_manager.h" 9#include "core/hle/service/hid/resource_manager.h"
10#include "core/hle/service/ipc_helpers.h" 10#include "core/hle/service/ipc_helpers.h"
11 11
12#include "core/hle/service/hid/controllers/console_sixaxis.h" 12#include "core/hle/service/hid/controllers/console_six_axis.h"
13#include "core/hle/service/hid/controllers/controller_base.h"
14#include "core/hle/service/hid/controllers/debug_pad.h" 13#include "core/hle/service/hid/controllers/debug_pad.h"
15#include "core/hle/service/hid/controllers/gesture.h" 14#include "core/hle/service/hid/controllers/gesture.h"
16#include "core/hle/service/hid/controllers/keyboard.h" 15#include "core/hle/service/hid/controllers/keyboard.h"
17#include "core/hle/service/hid/controllers/mouse.h" 16#include "core/hle/service/hid/controllers/mouse.h"
18#include "core/hle/service/hid/controllers/npad.h" 17#include "core/hle/service/hid/controllers/npad.h"
19#include "core/hle/service/hid/controllers/palma.h" 18#include "core/hle/service/hid/controllers/palma.h"
19#include "core/hle/service/hid/controllers/seven_six_axis.h"
20#include "core/hle/service/hid/controllers/six_axis.h"
20#include "core/hle/service/hid/controllers/stubbed.h" 21#include "core/hle/service/hid/controllers/stubbed.h"
21#include "core/hle/service/hid/controllers/touchscreen.h" 22#include "core/hle/service/hid/controllers/touchscreen.h"
22#include "core/hle/service/hid/controllers/xpad.h" 23#include "core/hle/service/hid/controllers/xpad.h"
@@ -42,76 +43,132 @@ void ResourceManager::Initialize() {
42 } 43 }
43 44
44 u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer(); 45 u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
45 MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory); 46 debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory);
46 MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory); 47 mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory);
47 MakeController<Controller_Mouse>(HidController::Mouse, shared_memory); 48 debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory);
48 MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory); 49 keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory);
49 MakeController<Controller_XPad>(HidController::XPad, shared_memory); 50 unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory);
50 MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory); 51 npad = std::make_shared<NPad>(system.HIDCore(), shared_memory, service_context);
51 MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory); 52 gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory);
52 MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory); 53 touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory);
53 MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory); 54 xpad = std::make_shared<XPad>(system.HIDCore(), shared_memory);
54 MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory); 55
55 MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory); 56 palma = std::make_shared<Palma>(system.HIDCore(), shared_memory, service_context);
56 MakeController<Controller_Gesture>(HidController::Gesture, shared_memory); 57
57 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory); 58 home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory);
58 MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory); 59 sleep_button = std::make_shared<SleepButton>(system.HIDCore(), shared_memory);
59 MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory); 60 capture_button = std::make_shared<CaptureButton>(system.HIDCore(), shared_memory);
61
62 six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
63 console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory);
64 seven_six_axis = std::make_shared<SevenSixAxis>(system);
65
66 home_button->SetCommonHeaderOffset(0x4C00);
67 sleep_button->SetCommonHeaderOffset(0x4E00);
68 capture_button->SetCommonHeaderOffset(0x5000);
69 unique_pad->SetCommonHeaderOffset(0x5A00);
70 debug_mouse->SetCommonHeaderOffset(0x3DC00);
60 71
61 // Homebrew doesn't try to activate some controllers, so we activate them by default 72 // Homebrew doesn't try to activate some controllers, so we activate them by default
62 GetController<Controller_NPad>(HidController::NPad).Activate(); 73 npad->Activate();
63 GetController<Controller_Touchscreen>(HidController::Touchscreen).Activate(); 74 six_axis->Activate();
64 75 touch_screen->Activate();
65 GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
66 GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
67 GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
68 GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
69 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
70 GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00);
71 76
72 system.HIDCore().ReloadInputDevices(); 77 system.HIDCore().ReloadInputDevices();
73 is_initialized = true; 78 is_initialized = true;
74} 79}
80std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const {
81 return capture_button;
82}
83
84std::shared_ptr<ConsoleSixAxis> ResourceManager::GetConsoleSixAxis() const {
85 return console_six_axis;
86}
87
88std::shared_ptr<DebugMouse> ResourceManager::GetDebugMouse() const {
89 return debug_mouse;
90}
91
92std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const {
93 return debug_pad;
94}
95
96std::shared_ptr<Gesture> ResourceManager::GetGesture() const {
97 return gesture;
98}
99
100std::shared_ptr<HomeButton> ResourceManager::GetHomeButton() const {
101 return home_button;
102}
103
104std::shared_ptr<Keyboard> ResourceManager::GetKeyboard() const {
105 return keyboard;
106}
107
108std::shared_ptr<Mouse> ResourceManager::GetMouse() const {
109 return mouse;
110}
111
112std::shared_ptr<NPad> ResourceManager::GetNpad() const {
113 return npad;
114}
115
116std::shared_ptr<Palma> ResourceManager::GetPalma() const {
117 return palma;
118}
119
120std::shared_ptr<SevenSixAxis> ResourceManager::GetSevenSixAxis() const {
121 return seven_six_axis;
122}
123
124std::shared_ptr<SixAxis> ResourceManager::GetSixAxis() const {
125 return six_axis;
126}
127
128std::shared_ptr<SleepButton> ResourceManager::GetSleepButton() const {
129 return sleep_button;
130}
131
132std::shared_ptr<TouchScreen> ResourceManager::GetTouchScreen() const {
133 return touch_screen;
134}
135
136std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const {
137 return unique_pad;
138}
75 139
76void ResourceManager::UpdateControllers(std::uintptr_t user_data, 140void ResourceManager::UpdateControllers(std::uintptr_t user_data,
77 std::chrono::nanoseconds ns_late) { 141 std::chrono::nanoseconds ns_late) {
78 auto& core_timing = system.CoreTiming(); 142 auto& core_timing = system.CoreTiming();
79 143 debug_pad->OnUpdate(core_timing);
80 for (const auto& controller : controllers) { 144 unique_pad->OnUpdate(core_timing);
81 // Keyboard has it's own update event 145 gesture->OnUpdate(core_timing);
82 if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) { 146 touch_screen->OnUpdate(core_timing);
83 continue; 147 palma->OnUpdate(core_timing);
84 } 148 home_button->OnUpdate(core_timing);
85 // Mouse has it's own update event 149 sleep_button->OnUpdate(core_timing);
86 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { 150 capture_button->OnUpdate(core_timing);
87 continue; 151 xpad->OnUpdate(core_timing);
88 }
89 // Npad has it's own update event
90 if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
91 continue;
92 }
93 controller->OnUpdate(core_timing);
94 }
95} 152}
96 153
97void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 154void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
98 auto& core_timing = system.CoreTiming(); 155 auto& core_timing = system.CoreTiming();
99 156 npad->OnUpdate(core_timing);
100 controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
101} 157}
102 158
103void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data, 159void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data,
104 std::chrono::nanoseconds ns_late) { 160 std::chrono::nanoseconds ns_late) {
105 auto& core_timing = system.CoreTiming(); 161 auto& core_timing = system.CoreTiming();
106 162 mouse->OnUpdate(core_timing);
107 controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); 163 debug_mouse->OnUpdate(core_timing);
108 controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); 164 keyboard->OnUpdate(core_timing);
109} 165}
110 166
111void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 167void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
112 auto& core_timing = system.CoreTiming(); 168 auto& core_timing = system.CoreTiming();
113 169 six_axis->OnUpdate(core_timing);
114 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); 170 seven_six_axis->OnUpdate(core_timing);
171 console_six_axis->OnUpdate(core_timing);
115} 172}
116 173
117IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource) 174IAppletResource::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 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <chrono>
7
8#include "core/core.h"
9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/kernel_helpers.h" 6#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
12 8
@@ -14,74 +10,85 @@ namespace Core::Timing {
14struct EventType; 10struct EventType;
15} 11}
16 12
17namespace Core::HID {
18class HIDCore;
19}
20
21namespace Service::HID { 13namespace Service::HID {
14class Controller_Stubbed;
15class ConsoleSixAxis;
16class DebugPad;
17class Gesture;
18class Keyboard;
19class Mouse;
20class NPad;
21class Palma;
22class SevenSixAxis;
23class SixAxis;
24class TouchScreen;
25class XPad;
26
27using CaptureButton = Controller_Stubbed;
28using DebugMouse = Controller_Stubbed;
29using HomeButton = Controller_Stubbed;
30using SleepButton = Controller_Stubbed;
31using UniquePad = Controller_Stubbed;
22 32
23enum class HidController : std::size_t {
24 DebugPad,
25 Touchscreen,
26 Mouse,
27 Keyboard,
28 XPad,
29 HomeButton,
30 SleepButton,
31 CaptureButton,
32 InputDetector,
33 UniquePad,
34 NPad,
35 Gesture,
36 ConsoleSixAxisSensor,
37 DebugMouse,
38 Palma,
39
40 MaxControllers,
41};
42class ResourceManager { 33class ResourceManager {
34
43public: 35public:
44 explicit ResourceManager(Core::System& system_); 36 explicit ResourceManager(Core::System& system_);
45 ~ResourceManager(); 37 ~ResourceManager();
46 38
47 template <typename T>
48 T& GetController(HidController controller) {
49 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
50 }
51
52 template <typename T>
53 const T& GetController(HidController controller) const {
54 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
55 }
56
57 void Initialize(); 39 void Initialize();
58 40
41 std::shared_ptr<CaptureButton> GetCaptureButton() const;
42 std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const;
43 std::shared_ptr<DebugMouse> GetDebugMouse() const;
44 std::shared_ptr<DebugPad> GetDebugPad() const;
45 std::shared_ptr<Gesture> GetGesture() const;
46 std::shared_ptr<HomeButton> GetHomeButton() const;
47 std::shared_ptr<Keyboard> GetKeyboard() const;
48 std::shared_ptr<Mouse> GetMouse() const;
49 std::shared_ptr<NPad> GetNpad() const;
50 std::shared_ptr<Palma> GetPalma() const;
51 std::shared_ptr<SevenSixAxis> GetSevenSixAxis() const;
52 std::shared_ptr<SixAxis> GetSixAxis() const;
53 std::shared_ptr<SleepButton> GetSleepButton() const;
54 std::shared_ptr<TouchScreen> GetTouchScreen() const;
55 std::shared_ptr<UniquePad> GetUniquePad() const;
56
59 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 57 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
60 void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 58 void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
61 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 59 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
62 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 60 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
63 61
64private: 62private:
65 template <typename T>
66 void MakeController(HidController controller, u8* shared_memory) {
67 if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
68 controllers[static_cast<std::size_t>(controller)] =
69 std::make_unique<T>(system, shared_memory);
70 } else {
71 controllers[static_cast<std::size_t>(controller)] =
72 std::make_unique<T>(system.HIDCore(), shared_memory);
73 }
74 }
75
76 template <typename T>
77 void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
78 controllers[static_cast<std::size_t>(controller)] =
79 std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
80 }
81
82 bool is_initialized{false}; 63 bool is_initialized{false};
83 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> 64
84 controllers{}; 65 std::shared_ptr<CaptureButton> capture_button = nullptr;
66 std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr;
67 std::shared_ptr<DebugMouse> debug_mouse = nullptr;
68 std::shared_ptr<DebugPad> debug_pad = nullptr;
69 std::shared_ptr<Gesture> gesture = nullptr;
70 std::shared_ptr<HomeButton> home_button = nullptr;
71 std::shared_ptr<Keyboard> keyboard = nullptr;
72 std::shared_ptr<Mouse> mouse = nullptr;
73 std::shared_ptr<NPad> npad = nullptr;
74 std::shared_ptr<Palma> palma = nullptr;
75 std::shared_ptr<SevenSixAxis> seven_six_axis = nullptr;
76 std::shared_ptr<SixAxis> six_axis = nullptr;
77 std::shared_ptr<SleepButton> sleep_button = nullptr;
78 std::shared_ptr<TouchScreen> touch_screen = nullptr;
79 std::shared_ptr<UniquePad> unique_pad = nullptr;
80 std::shared_ptr<XPad> xpad = nullptr;
81
82 // TODO: Create these resources
83 // std::shared_ptr<AudioControl> audio_control = nullptr;
84 // std::shared_ptr<ButtonConfig> button_config = nullptr;
85 // std::shared_ptr<Config> config = nullptr;
86 // std::shared_ptr<Connection> connection = nullptr;
87 // std::shared_ptr<CustomConfig> custom_config = nullptr;
88 // std::shared_ptr<Digitizer> digitizer = nullptr;
89 // std::shared_ptr<Hdls> hdls = nullptr;
90 // std::shared_ptr<PlayReport> play_report = nullptr;
91 // std::shared_ptr<Rail> rail = nullptr;
85 92
86 Core::System& system; 93 Core::System& system;
87 KernelHelpers::ServiceContext service_context; 94 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 @@
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hid/hid_types.h" 8#include "core/hid/hid_types.h"
9#include "core/hle/kernel/k_event.h" 9#include "core/hle/kernel/k_event.h"
10#include "core/hle/service/hid/hid_util.h"
10#include "core/hle/service/ipc_helpers.h" 11#include "core/hle/service/ipc_helpers.h"
11#include "core/hle/service/nfc/common/device.h" 12#include "core/hle/service/nfc/common/device.h"
12#include "core/hle/service/nfc/common/device_manager.h" 13#include "core/hle/service/nfc/common/device_manager.h"
@@ -24,7 +25,7 @@ DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContex
24 25
25 for (u32 device_index = 0; device_index < devices.size(); device_index++) { 26 for (u32 device_index = 0; device_index < devices.size(); device_index++) {
26 devices[device_index] = 27 devices[device_index] =
27 std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, 28 std::make_shared<NfcDevice>(HID::IndexToNpadIdType(device_index), system,
28 service_context, availability_change_event); 29 service_context, availability_change_event);
29 } 30 }
30 31
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() {
68 return 0; 68 return 0;
69 } 69 }
70 70
71 const auto press_state = 71 const auto press_state = applet_resource->GetNpad()->GetAndResetPressState();
72 applet_resource
73 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)
74 .GetAndResetPressState();
75 return static_cast<u64>(press_state & HID::NpadButton::All); 72 return static_cast<u64>(press_state & HID::NpadButton::All);
76} 73}
77 74
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 @@
1# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2# SPDX-License-Identifier: GPL-2.0-or-later
3
4add_library(frontend_common STATIC
5 config.cpp
6 config.h
7)
8
9create_target_directory_groups(frontend_common)
10target_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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include "common/fs/fs.h"
7#include "common/fs/path_util.h"
8#include "common/settings.h"
9#include "common/settings_common.h"
10#include "common/settings_enums.h"
11#include "config.h"
12#include "core/core.h"
13#include "core/hle/service/acc/profile_manager.h"
14#include "core/hle/service/hid/controllers/npad.h"
15#include "network/network.h"
16
17#include <boost/algorithm/string/replace.hpp>
18
19#include "common/string_util.h"
20
21namespace FS = Common::FS;
22
23Config::Config(const ConfigType config_type)
24 : type(config_type), global{config_type == ConfigType::GlobalConfig} {}
25
26void Config::Initialize(const std::string& config_name) {
27 const std::filesystem::path fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir);
28 const auto config_file = fmt::format("{}.ini", config_name);
29
30 switch (type) {
31 case ConfigType::GlobalConfig:
32 config_loc = FS::PathToUTF8String(fs_config_loc / config_file);
33 void(FS::CreateParentDir(config_loc));
34 SetUpIni();
35 Reload();
36 break;
37 case ConfigType::PerGameConfig:
38 config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file));
39 void(FS::CreateParentDir(config_loc));
40 SetUpIni();
41 Reload();
42 break;
43 case ConfigType::InputProfile:
44 config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file);
45 void(FS::CreateParentDir(config_loc));
46 SetUpIni();
47 break;
48 }
49}
50
51void Config::Initialize(const std::optional<std::string> config_path) {
52 const std::filesystem::path default_sdl_config_path =
53 FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini";
54 config_loc = config_path.value_or(FS::PathToUTF8String(default_sdl_config_path));
55 void(FS::CreateParentDir(config_loc));
56 SetUpIni();
57 Reload();
58}
59
60void Config::WriteToIni() const {
61 FILE* fp = nullptr;
62#ifdef _WIN32
63 fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb");
64#else
65 fp = fopen(config_loc.c_str(), "wb");
66#endif
67
68 if (fp == nullptr) {
69 LOG_ERROR(Frontend, "Config file could not be saved!");
70 return;
71 }
72
73 CSimpleIniA::FileWriter writer(fp);
74 const SI_Error rc = config->Save(writer, false);
75 if (rc < 0) {
76 LOG_ERROR(Frontend, "Config file could not be saved!");
77 }
78 fclose(fp);
79}
80
81void Config::SetUpIni() {
82 config = std::make_unique<CSimpleIniA>();
83 config->SetUnicode(true);
84 config->SetSpaces(false);
85
86 FILE* fp = nullptr;
87#ifdef _WIN32
88 _wfopen_s(&fp, Common::UTF8ToUTF16W(config_loc).data(), L"rb, ccs=UTF-8");
89 if (fp == nullptr) {
90 fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb, ccs=UTF-8");
91 }
92#else
93 fp = fopen(config_loc.c_str(), "rb");
94 if (fp == nullptr) {
95 fp = fopen(config_loc.c_str(), "wb");
96 }
97#endif
98
99 if (fp == nullptr) {
100 LOG_ERROR(Frontend, "Config file could not be loaded!");
101 return;
102 }
103
104 if (SI_Error rc = config->LoadFile(fp); rc < 0) {
105 LOG_ERROR(Frontend, "Config file could not be loaded!");
106 }
107 fclose(fp);
108}
109
110bool Config::IsCustomConfig() const {
111 return type == ConfigType::PerGameConfig;
112}
113
114void Config::ReadPlayerValues(const std::size_t player_index) {
115 std::string player_prefix;
116 if (type != ConfigType::InputProfile) {
117 player_prefix.append("player_").append(ToString(player_index)).append("_");
118 }
119
120 auto& player = Settings::values.players.GetValue()[player_index];
121 if (IsCustomConfig()) {
122 const auto profile_name =
123 ReadStringSetting(std::string(player_prefix).append("profile_name"));
124 if (profile_name.empty()) {
125 // Use the global input config
126 player = Settings::values.players.GetValue(true)[player_index];
127 return;
128 }
129 player.profile_name = profile_name;
130 }
131
132 if (player_prefix.empty() && Settings::IsConfiguringGlobal()) {
133 const auto controller = static_cast<Settings::ControllerType>(
134 ReadIntegerSetting(std::string(player_prefix).append("type"),
135 static_cast<u8>(Settings::ControllerType::ProController)));
136
137 if (controller == Settings::ControllerType::LeftJoycon ||
138 controller == Settings::ControllerType::RightJoycon) {
139 player.controller_type = controller;
140 }
141 } else {
142 std::string connected_key = player_prefix;
143 player.connected = ReadBooleanSetting(connected_key.append("connected"),
144 std::make_optional(player_index == 0));
145
146 player.controller_type = static_cast<Settings::ControllerType>(
147 ReadIntegerSetting(std::string(player_prefix).append("type"),
148 static_cast<u8>(Settings::ControllerType::ProController)));
149
150 player.vibration_enabled = ReadBooleanSetting(
151 std::string(player_prefix).append("vibration_enabled"), std::make_optional(true));
152
153 player.vibration_strength = static_cast<int>(
154 ReadIntegerSetting(std::string(player_prefix).append("vibration_strength"), 100));
155
156 player.body_color_left = static_cast<u32>(ReadIntegerSetting(
157 std::string(player_prefix).append("body_color_left"), Settings::JOYCON_BODY_NEON_BLUE));
158 player.body_color_right = static_cast<u32>(ReadIntegerSetting(
159 std::string(player_prefix).append("body_color_right"), Settings::JOYCON_BODY_NEON_RED));
160 player.button_color_left = static_cast<u32>(
161 ReadIntegerSetting(std::string(player_prefix).append("button_color_left"),
162 Settings::JOYCON_BUTTONS_NEON_BLUE));
163 player.button_color_right = static_cast<u32>(
164 ReadIntegerSetting(std::string(player_prefix).append("button_color_right"),
165 Settings::JOYCON_BUTTONS_NEON_RED));
166 }
167}
168
169void Config::ReadTouchscreenValues() {
170 Settings::values.touchscreen.enabled =
171 ReadBooleanSetting(std::string("touchscreen_enabled"), std::make_optional(true));
172 Settings::values.touchscreen.rotation_angle =
173 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_angle"), 0));
174 Settings::values.touchscreen.diameter_x =
175 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_x"), 15));
176 Settings::values.touchscreen.diameter_y =
177 static_cast<u32>(ReadIntegerSetting(std::string("touchscreen_diameter_y"), 15));
178}
179
180void Config::ReadAudioValues() {
181 BeginGroup(Settings::TranslateCategory(Settings::Category::Audio));
182
183 ReadCategory(Settings::Category::Audio);
184 ReadCategory(Settings::Category::UiAudio);
185
186 EndGroup();
187}
188
189void Config::ReadControlValues() {
190 BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
191
192 ReadCategory(Settings::Category::Controls);
193
194 Settings::values.players.SetGlobal(!IsCustomConfig());
195 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
196 ReadPlayerValues(p);
197 }
198
199 // Disable docked mode if handheld is selected
200 const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
201 if (controller_type == Settings::ControllerType::Handheld) {
202 Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig());
203 Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld);
204 }
205
206 if (IsCustomConfig()) {
207 EndGroup();
208 return;
209 }
210 ReadTouchscreenValues();
211 ReadMotionTouchValues();
212
213 EndGroup();
214}
215
216void Config::ReadMotionTouchValues() {
217 int num_touch_from_button_maps = BeginArray(std::string("touch_from_button_maps"));
218
219 if (num_touch_from_button_maps > 0) {
220 for (int i = 0; i < num_touch_from_button_maps; ++i) {
221 SetArrayIndex(i);
222
223 Settings::TouchFromButtonMap map;
224 map.name = ReadStringSetting(std::string("name"), std::string("default"));
225
226 const int num_touch_maps = BeginArray(std::string("entries"));
227 map.buttons.reserve(num_touch_maps);
228 for (int j = 0; j < num_touch_maps; j++) {
229 SetArrayIndex(j);
230 std::string touch_mapping = ReadStringSetting(std::string("bind"));
231 map.buttons.emplace_back(std::move(touch_mapping));
232 }
233 EndArray(); // entries
234 Settings::values.touch_from_button_maps.emplace_back(std::move(map));
235 }
236 } else {
237 Settings::values.touch_from_button_maps.emplace_back(
238 Settings::TouchFromButtonMap{"default", {}});
239 num_touch_from_button_maps = 1;
240 }
241 EndArray(); // touch_from_button_maps
242
243 Settings::values.touch_from_button_map_index = std::clamp(
244 Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
245}
246
247void Config::ReadCoreValues() {
248 BeginGroup(Settings::TranslateCategory(Settings::Category::Core));
249
250 ReadCategory(Settings::Category::Core);
251
252 EndGroup();
253}
254
255void Config::ReadDataStorageValues() {
256 BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage));
257
258 FS::SetYuzuPath(FS::YuzuPath::NANDDir, ReadStringSetting(std::string("nand_directory")));
259 FS::SetYuzuPath(FS::YuzuPath::SDMCDir, ReadStringSetting(std::string("sdmc_directory")));
260 FS::SetYuzuPath(FS::YuzuPath::LoadDir, ReadStringSetting(std::string("load_directory")));
261 FS::SetYuzuPath(FS::YuzuPath::DumpDir, ReadStringSetting(std::string("dump_directory")));
262 FS::SetYuzuPath(FS::YuzuPath::TASDir, ReadStringSetting(std::string("tas_directory")));
263
264 ReadCategory(Settings::Category::DataStorage);
265
266 EndGroup();
267}
268
269void Config::ReadDebuggingValues() {
270 BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging));
271
272 // Intentionally not using the QT default setting as this is intended to be changed in the ini
273 Settings::values.record_frame_times =
274 ReadBooleanSetting(std::string("record_frame_times"), std::make_optional(false));
275
276 ReadCategory(Settings::Category::Debugging);
277 ReadCategory(Settings::Category::DebuggingGraphics);
278
279 EndGroup();
280}
281
282void Config::ReadServiceValues() {
283 BeginGroup(Settings::TranslateCategory(Settings::Category::Services));
284
285 ReadCategory(Settings::Category::Services);
286
287 EndGroup();
288}
289
290void Config::ReadDisabledAddOnValues() {
291 // Custom config section
292 BeginGroup(std::string("DisabledAddOns"));
293
294 const int size = BeginArray(std::string(""));
295 for (int i = 0; i < size; ++i) {
296 SetArrayIndex(i);
297 const auto title_id = ReadUnsignedIntegerSetting(std::string("title_id"), 0);
298 std::vector<std::string> out;
299 const int d_size = BeginArray("disabled");
300 for (int j = 0; j < d_size; ++j) {
301 SetArrayIndex(j);
302 out.push_back(ReadStringSetting(std::string("d"), std::string("")));
303 }
304 EndArray(); // d
305 Settings::values.disabled_addons.insert_or_assign(title_id, out);
306 }
307 EndArray(); // Base disabled addons array - Has no base key
308
309 EndGroup();
310}
311
312void Config::ReadMiscellaneousValues() {
313 BeginGroup(Settings::TranslateCategory(Settings::Category::Miscellaneous));
314
315 ReadCategory(Settings::Category::Miscellaneous);
316
317 EndGroup();
318}
319
320void Config::ReadCpuValues() {
321 BeginGroup(Settings::TranslateCategory(Settings::Category::Cpu));
322
323 ReadCategory(Settings::Category::Cpu);
324 ReadCategory(Settings::Category::CpuDebug);
325 ReadCategory(Settings::Category::CpuUnsafe);
326
327 EndGroup();
328}
329
330void Config::ReadRendererValues() {
331 BeginGroup(Settings::TranslateCategory(Settings::Category::Renderer));
332
333 ReadCategory(Settings::Category::Renderer);
334 ReadCategory(Settings::Category::RendererAdvanced);
335 ReadCategory(Settings::Category::RendererDebug);
336
337 EndGroup();
338}
339
340void Config::ReadScreenshotValues() {
341 BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots));
342
343 ReadCategory(Settings::Category::Screenshots);
344 FS::SetYuzuPath(FS::YuzuPath::ScreenshotsDir,
345 ReadStringSetting(std::string("screenshot_path")));
346
347 EndGroup();
348}
349
350void Config::ReadSystemValues() {
351 BeginGroup(Settings::TranslateCategory(Settings::Category::System));
352
353 ReadCategory(Settings::Category::System);
354 ReadCategory(Settings::Category::SystemAudio);
355
356 EndGroup();
357}
358
359void Config::ReadWebServiceValues() {
360 BeginGroup(Settings::TranslateCategory(Settings::Category::WebService));
361
362 ReadCategory(Settings::Category::WebService);
363
364 EndGroup();
365}
366
367void Config::ReadNetworkValues() {
368 BeginGroup(Settings::TranslateCategory(Settings::Category::Services));
369
370 ReadCategory(Settings::Category::Network);
371
372 EndGroup();
373}
374
375void Config::ReadValues() {
376 if (global) {
377 ReadDataStorageValues();
378 ReadDebuggingValues();
379 ReadDisabledAddOnValues();
380 ReadNetworkValues();
381 ReadServiceValues();
382 ReadWebServiceValues();
383 ReadMiscellaneousValues();
384 }
385 ReadControlValues();
386 ReadCoreValues();
387 ReadCpuValues();
388 ReadRendererValues();
389 ReadAudioValues();
390 ReadSystemValues();
391}
392
393void Config::SavePlayerValues(const std::size_t player_index) {
394 std::string player_prefix;
395 if (type != ConfigType::InputProfile) {
396 player_prefix = std::string("player_").append(ToString(player_index)).append("_");
397 }
398
399 const auto& player = Settings::values.players.GetValue()[player_index];
400 if (IsCustomConfig()) {
401 if (player.profile_name.empty()) {
402 // No custom profile selected
403 return;
404 }
405 WriteSetting(std::string(player_prefix).append("profile_name"), player.profile_name,
406 std::make_optional(std::string("")));
407 }
408
409 WriteSetting(std::string(player_prefix).append("type"), static_cast<u8>(player.controller_type),
410 std::make_optional(static_cast<u8>(Settings::ControllerType::ProController)));
411
412 if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) {
413 WriteSetting(std::string(player_prefix).append("connected"), player.connected,
414 std::make_optional(player_index == 0));
415 WriteSetting(std::string(player_prefix).append("vibration_enabled"),
416 player.vibration_enabled, std::make_optional(true));
417 WriteSetting(std::string(player_prefix).append("vibration_strength"),
418 player.vibration_strength, std::make_optional(100));
419 WriteSetting(std::string(player_prefix).append("body_color_left"), player.body_color_left,
420 std::make_optional(Settings::JOYCON_BODY_NEON_BLUE));
421 WriteSetting(std::string(player_prefix).append("body_color_right"), player.body_color_right,
422 std::make_optional(Settings::JOYCON_BODY_NEON_RED));
423 WriteSetting(std::string(player_prefix).append("button_color_left"),
424 player.button_color_left,
425 std::make_optional(Settings::JOYCON_BUTTONS_NEON_BLUE));
426 WriteSetting(std::string(player_prefix).append("button_color_right"),
427 player.button_color_right,
428 std::make_optional(Settings::JOYCON_BUTTONS_NEON_RED));
429 }
430}
431
432void Config::SaveTouchscreenValues() {
433 const auto& touchscreen = Settings::values.touchscreen;
434
435 WriteSetting(std::string("touchscreen_enabled"), touchscreen.enabled, std::make_optional(true));
436
437 WriteSetting(std::string("touchscreen_angle"), touchscreen.rotation_angle,
438 std::make_optional(static_cast<u32>(0)));
439 WriteSetting(std::string("touchscreen_diameter_x"), touchscreen.diameter_x,
440 std::make_optional(static_cast<u32>(15)));
441 WriteSetting(std::string("touchscreen_diameter_y"), touchscreen.diameter_y,
442 std::make_optional(static_cast<u32>(15)));
443}
444
445void Config::SaveMotionTouchValues() {
446 BeginArray(std::string("touch_from_button_maps"));
447 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
448 SetArrayIndex(static_cast<int>(p));
449 WriteSetting(std::string("name"), Settings::values.touch_from_button_maps[p].name,
450 std::make_optional(std::string("default")));
451
452 BeginArray(std::string("entries"));
453 for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size();
454 ++q) {
455 SetArrayIndex(static_cast<int>(q));
456 WriteSetting(std::string("bind"),
457 Settings::values.touch_from_button_maps[p].buttons[q]);
458 }
459 EndArray(); // entries
460 }
461 EndArray(); // touch_from_button_maps
462}
463
464void Config::SaveValues() {
465 if (global) {
466 SaveDataStorageValues();
467 SaveDebuggingValues();
468 SaveDisabledAddOnValues();
469 SaveNetworkValues();
470 SaveWebServiceValues();
471 SaveMiscellaneousValues();
472 }
473 SaveControlValues();
474 SaveCoreValues();
475 SaveCpuValues();
476 SaveRendererValues();
477 SaveAudioValues();
478 SaveSystemValues();
479
480 WriteToIni();
481}
482
483void Config::SaveAudioValues() {
484 BeginGroup(Settings::TranslateCategory(Settings::Category::Audio));
485
486 WriteCategory(Settings::Category::Audio);
487 WriteCategory(Settings::Category::UiAudio);
488
489 EndGroup();
490}
491
492void Config::SaveControlValues() {
493 BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
494
495 WriteCategory(Settings::Category::Controls);
496
497 Settings::values.players.SetGlobal(!IsCustomConfig());
498 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
499 SavePlayerValues(p);
500 }
501 if (IsCustomConfig()) {
502 EndGroup();
503 return;
504 }
505 SaveTouchscreenValues();
506 SaveMotionTouchValues();
507
508 EndGroup();
509}
510
511void Config::SaveCoreValues() {
512 BeginGroup(Settings::TranslateCategory(Settings::Category::Core));
513
514 WriteCategory(Settings::Category::Core);
515
516 EndGroup();
517}
518
519void Config::SaveDataStorageValues() {
520 BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage));
521
522 WriteSetting(std::string("nand_directory"), FS::GetYuzuPathString(FS::YuzuPath::NANDDir),
523 std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
524 WriteSetting(std::string("sdmc_directory"), FS::GetYuzuPathString(FS::YuzuPath::SDMCDir),
525 std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
526 WriteSetting(std::string("load_directory"), FS::GetYuzuPathString(FS::YuzuPath::LoadDir),
527 std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
528 WriteSetting(std::string("dump_directory"), FS::GetYuzuPathString(FS::YuzuPath::DumpDir),
529 std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
530 WriteSetting(std::string("tas_directory"), FS::GetYuzuPathString(FS::YuzuPath::TASDir),
531 std::make_optional(FS::GetYuzuPathString(FS::YuzuPath::TASDir)));
532
533 WriteCategory(Settings::Category::DataStorage);
534
535 EndGroup();
536}
537
538void Config::SaveDebuggingValues() {
539 BeginGroup(Settings::TranslateCategory(Settings::Category::Debugging));
540
541 // Intentionally not using the QT default setting as this is intended to be changed in the ini
542 WriteSetting(std::string("record_frame_times"), Settings::values.record_frame_times);
543
544 WriteCategory(Settings::Category::Debugging);
545 WriteCategory(Settings::Category::DebuggingGraphics);
546
547 EndGroup();
548}
549
550void Config::SaveNetworkValues() {
551 BeginGroup(Settings::TranslateCategory(Settings::Category::Services));
552
553 WriteCategory(Settings::Category::Network);
554
555 EndGroup();
556}
557
558void Config::SaveDisabledAddOnValues() {
559 // Custom config section
560 BeginGroup(std::string("DisabledAddOns"));
561
562 int i = 0;
563 BeginArray(std::string(""));
564 for (const auto& elem : Settings::values.disabled_addons) {
565 SetArrayIndex(i);
566 WriteSetting(std::string("title_id"), elem.first, std::make_optional(static_cast<u64>(0)));
567 BeginArray(std::string("disabled"));
568 for (std::size_t j = 0; j < elem.second.size(); ++j) {
569 SetArrayIndex(static_cast<int>(j));
570 WriteSetting(std::string("d"), elem.second[j], std::make_optional(std::string("")));
571 }
572 EndArray(); // disabled
573 ++i;
574 }
575 EndArray(); // Base disabled addons array - Has no base key
576
577 EndGroup();
578}
579
580void Config::SaveMiscellaneousValues() {
581 BeginGroup(Settings::TranslateCategory(Settings::Category::Miscellaneous));
582
583 WriteCategory(Settings::Category::Miscellaneous);
584
585 EndGroup();
586}
587
588void Config::SaveCpuValues() {
589 BeginGroup(Settings::TranslateCategory(Settings::Category::Cpu));
590
591 WriteCategory(Settings::Category::Cpu);
592 WriteCategory(Settings::Category::CpuDebug);
593 WriteCategory(Settings::Category::CpuUnsafe);
594
595 EndGroup();
596}
597
598void Config::SaveRendererValues() {
599 BeginGroup(Settings::TranslateCategory(Settings::Category::Renderer));
600
601 WriteCategory(Settings::Category::Renderer);
602 WriteCategory(Settings::Category::RendererAdvanced);
603 WriteCategory(Settings::Category::RendererDebug);
604
605 EndGroup();
606}
607
608void Config::SaveScreenshotValues() {
609 BeginGroup(Settings::TranslateCategory(Settings::Category::Screenshots));
610
611 WriteSetting(std::string("screenshot_path"),
612 FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir));
613 WriteCategory(Settings::Category::Screenshots);
614
615 EndGroup();
616}
617
618void Config::SaveSystemValues() {
619 BeginGroup(Settings::TranslateCategory(Settings::Category::System));
620
621 WriteCategory(Settings::Category::System);
622 WriteCategory(Settings::Category::SystemAudio);
623
624 EndGroup();
625}
626
627void Config::SaveWebServiceValues() {
628 BeginGroup(Settings::TranslateCategory(Settings::Category::WebService));
629
630 WriteCategory(Settings::Category::WebService);
631
632 EndGroup();
633}
634
635bool Config::ReadBooleanSetting(const std::string& key, const std::optional<bool> default_value) {
636 std::string full_key = GetFullKey(key, false);
637 if (!default_value.has_value()) {
638 return config->GetBoolValue(GetSection().c_str(), full_key.c_str(), false);
639 }
640
641 if (config->GetBoolValue(GetSection().c_str(),
642 std::string(full_key).append("\\default").c_str(), false)) {
643 return static_cast<bool>(default_value.value());
644 } else {
645 return config->GetBoolValue(GetSection().c_str(), full_key.c_str(),
646 static_cast<bool>(default_value.value()));
647 }
648}
649
650s64 Config::ReadIntegerSetting(const std::string& key, const std::optional<s64> default_value) {
651 std::string full_key = GetFullKey(key, false);
652 if (!default_value.has_value()) {
653 try {
654 return std::stoll(
655 std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0")));
656 } catch (...) {
657 return 0;
658 }
659 }
660
661 s64 result = 0;
662 if (config->GetBoolValue(GetSection().c_str(),
663 std::string(full_key).append("\\default").c_str(), true)) {
664 result = default_value.value();
665 } else {
666 try {
667 result = std::stoll(std::string(config->GetValue(
668 GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str())));
669 } catch (...) {
670 result = default_value.value();
671 }
672 }
673 return result;
674}
675
676u64 Config::ReadUnsignedIntegerSetting(const std::string& key,
677 const std::optional<u64> default_value) {
678 std::string full_key = GetFullKey(key, false);
679 if (!default_value.has_value()) {
680 try {
681 return std::stoull(
682 std::string(config->GetValue(GetSection().c_str(), full_key.c_str(), "0")));
683 } catch (...) {
684 return 0;
685 }
686 }
687
688 u64 result = 0;
689 if (config->GetBoolValue(GetSection().c_str(),
690 std::string(full_key).append("\\default").c_str(), true)) {
691 result = default_value.value();
692 } else {
693 try {
694 result = std::stoull(std::string(config->GetValue(
695 GetSection().c_str(), full_key.c_str(), ToString(default_value.value()).c_str())));
696 } catch (...) {
697 result = default_value.value();
698 }
699 }
700 return result;
701}
702
703double Config::ReadDoubleSetting(const std::string& key,
704 const std::optional<double> default_value) {
705 std::string full_key = GetFullKey(key, false);
706 if (!default_value.has_value()) {
707 return config->GetDoubleValue(GetSection().c_str(), full_key.c_str(), 0);
708 }
709
710 double result;
711 if (config->GetBoolValue(GetSection().c_str(),
712 std::string(full_key).append("\\default").c_str(), true)) {
713 result = default_value.value();
714 } else {
715 result =
716 config->GetDoubleValue(GetSection().c_str(), full_key.c_str(), default_value.value());
717 }
718 return result;
719}
720
721std::string Config::ReadStringSetting(const std::string& key,
722 const std::optional<std::string> default_value) {
723 std::string result;
724 std::string full_key = GetFullKey(key, false);
725 if (!default_value.has_value()) {
726 result = config->GetValue(GetSection().c_str(), full_key.c_str(), "");
727 boost::replace_all(result, "\"", "");
728 return result;
729 }
730
731 if (config->GetBoolValue(GetSection().c_str(),
732 std::string(full_key).append("\\default").c_str(), true)) {
733 result = default_value.value();
734 } else {
735 result =
736 config->GetValue(GetSection().c_str(), full_key.c_str(), default_value.value().c_str());
737 }
738 boost::replace_all(result, "\"", "");
739 boost::replace_all(result, "//", "/");
740 return result;
741}
742
743bool Config::Exists(const std::string& section, const std::string& key) const {
744 const std::string value = config->GetValue(section.c_str(), key.c_str(), "");
745 return !value.empty();
746}
747
748template <typename Type>
749void Config::WriteSetting(const std::string& key, const Type& value,
750 const std::optional<Type>& default_value,
751 const std::optional<bool>& use_global) {
752 std::string full_key = GetFullKey(key, false);
753
754 std::string saved_value;
755 std::string string_default;
756 if constexpr (std::is_same_v<Type, std::string>) {
757 saved_value.append(AdjustOutputString(value));
758 if (default_value.has_value()) {
759 string_default.append(AdjustOutputString(default_value.value()));
760 }
761 } else {
762 saved_value.append(AdjustOutputString(ToString(value)));
763 if (default_value.has_value()) {
764 string_default.append(ToString(default_value.value()));
765 }
766 }
767
768 if (default_value.has_value() && use_global.has_value()) {
769 if (!global) {
770 WriteSettingInternal(std::string(full_key).append("\\global"),
771 ToString(use_global.value()));
772 }
773 if (global || use_global.value() == false) {
774 WriteSettingInternal(std::string(full_key).append("\\default"),
775 ToString(string_default == saved_value));
776 WriteSettingInternal(full_key, saved_value);
777 }
778 } else if (default_value.has_value() && !use_global.has_value()) {
779 WriteSettingInternal(std::string(full_key).append("\\default"),
780 ToString(string_default == saved_value));
781 WriteSettingInternal(full_key, saved_value);
782 } else {
783 WriteSettingInternal(full_key, saved_value);
784 }
785}
786
787void Config::WriteSettingInternal(const std::string& key, const std::string& value) {
788 config->SetValue(GetSection().c_str(), key.c_str(), value.c_str());
789}
790
791void Config::Reload() {
792 ReadValues();
793 // To apply default value changes
794 SaveValues();
795}
796
797void Config::Save() {
798 SaveValues();
799}
800
801void Config::ClearControlPlayerValues() const {
802 // If key is an empty string, all keys in the current group() are removed.
803 const char* section = Settings::TranslateCategory(Settings::Category::Controls);
804 CSimpleIniA::TNamesDepend keys;
805 config->GetAllKeys(section, keys);
806 for (const auto& key : keys) {
807 if (std::string(config->GetValue(section, key.pItem)).empty()) {
808 config->Delete(section, key.pItem);
809 }
810 }
811}
812
813const std::string& Config::GetConfigFilePath() const {
814 return config_loc;
815}
816
817void Config::ReadCategory(const Settings::Category category) {
818 const auto& settings = FindRelevantList(category);
819 std::ranges::for_each(settings, [&](const auto& setting) { ReadSettingGeneric(setting); });
820}
821
822void Config::WriteCategory(const Settings::Category category) {
823 const auto& settings = FindRelevantList(category);
824 std::ranges::for_each(settings, [&](const auto& setting) { WriteSettingGeneric(setting); });
825}
826
827void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) {
828 if (!setting->Save() || (!setting->Switchable() && !global)) {
829 return;
830 }
831
832 const std::string key = AdjustKey(setting->GetLabel());
833 const std::string default_value(setting->DefaultToString());
834
835 bool use_global = true;
836 if (setting->Switchable() && !global) {
837 use_global =
838 ReadBooleanSetting(std::string(key).append("\\use_global"), std::make_optional(true));
839 setting->SetGlobal(use_global);
840 }
841
842 if (global || !use_global) {
843 const bool is_default =
844 ReadBooleanSetting(std::string(key).append("\\default"), std::make_optional(true));
845 if (!is_default) {
846 const std::string setting_string = ReadStringSetting(key, default_value);
847 setting->LoadString(setting_string);
848 } else {
849 // Empty string resets the Setting to default
850 setting->LoadString("");
851 }
852 }
853}
854
855void Config::WriteSettingGeneric(const Settings::BasicSetting* const setting) {
856 if (!setting->Save()) {
857 return;
858 }
859
860 std::string key = AdjustKey(setting->GetLabel());
861 if (setting->Switchable()) {
862 if (!global) {
863 WriteSetting(std::string(key).append("\\use_global"), setting->UsingGlobal());
864 }
865 if (global || !setting->UsingGlobal()) {
866 WriteSetting(std::string(key).append("\\default"),
867 setting->ToString() == setting->DefaultToString());
868 WriteSetting(key, setting->ToString());
869 }
870 } else if (global) {
871 WriteSetting(std::string(key).append("\\default"),
872 setting->ToString() == setting->DefaultToString());
873 WriteSetting(key, setting->ToString());
874 }
875}
876
877void Config::BeginGroup(const std::string& group) {
878 // You can't begin a group while reading/writing from a config array
879 ASSERT(array_stack.empty());
880
881 key_stack.push_back(AdjustKey(group));
882}
883
884void Config::EndGroup() {
885 // You can't end a group if you haven't started one yet
886 ASSERT(!key_stack.empty());
887
888 // You can't end a group when reading/writing from a config array
889 ASSERT(array_stack.empty());
890
891 key_stack.pop_back();
892}
893
894std::string Config::GetSection() {
895 if (key_stack.empty()) {
896 return std::string{""};
897 }
898
899 return key_stack.front();
900}
901
902std::string Config::GetGroup() const {
903 if (key_stack.size() <= 1) {
904 return std::string{""};
905 }
906
907 std::string key;
908 for (size_t i = 1; i < key_stack.size(); ++i) {
909 key.append(key_stack[i]).append("\\");
910 }
911 return key;
912}
913
914std::string Config::AdjustKey(const std::string& key) {
915 std::string adjusted_key(key);
916 boost::replace_all(adjusted_key, "/", "\\");
917 boost::replace_all(adjusted_key, " ", "%20");
918 return adjusted_key;
919}
920
921std::string Config::AdjustOutputString(const std::string& string) {
922 std::string adjusted_string(string);
923 boost::replace_all(adjusted_string, "\\", "/");
924
925 // Windows requires that two forward slashes are used at the start of a path for unmapped
926 // network drives so we have to watch for that here
927 if (string.substr(0, 2) == "//") {
928 boost::replace_all(adjusted_string, "//", "/");
929 adjusted_string.insert(0, "/");
930 } else {
931 boost::replace_all(adjusted_string, "//", "/");
932 }
933
934 // Needed for backwards compatibility with QSettings deserialization
935 for (const auto& special_character : special_characters) {
936 if (adjusted_string.find(special_character) != std::string::npos) {
937 adjusted_string.insert(0, "\"");
938 adjusted_string.append("\"");
939 break;
940 }
941 }
942 return adjusted_string;
943}
944
945std::string Config::GetFullKey(const std::string& key, bool skipArrayIndex) {
946 if (array_stack.empty()) {
947 return std::string(GetGroup()).append(AdjustKey(key));
948 }
949
950 std::string array_key;
951 for (size_t i = 0; i < array_stack.size(); ++i) {
952 if (!array_stack[i].name.empty()) {
953 array_key.append(array_stack[i].name).append("\\");
954 }
955
956 if (!skipArrayIndex || (array_stack.size() - 1 != i && array_stack.size() > 1)) {
957 array_key.append(ToString(array_stack[i].index)).append("\\");
958 }
959 }
960 std::string final_key = std::string(GetGroup()).append(array_key).append(AdjustKey(key));
961 return final_key;
962}
963
964int Config::BeginArray(const std::string& array) {
965 array_stack.push_back(ConfigArray{AdjustKey(array), 0, 0});
966 const int size = config->GetLongValue(GetSection().c_str(),
967 GetFullKey(std::string("size"), true).c_str(), 0);
968 array_stack.back().size = size;
969 return size;
970}
971
972void Config::EndArray() {
973 // You can't end a config array before starting one
974 ASSERT(!array_stack.empty());
975
976 // Set the array size to 0 if the array is ended without changing the index
977 int size = 0;
978 if (array_stack.back().index != 0) {
979 size = array_stack.back().size;
980 }
981
982 // Write out the size to config
983 if (key_stack.size() == 1 && array_stack.back().name.empty()) {
984 // Edge-case where the first array created doesn't have a name
985 config->SetValue(GetSection().c_str(), std::string("size").c_str(), ToString(size).c_str());
986 } else {
987 const auto key = GetFullKey(std::string("size"), true);
988 config->SetValue(GetSection().c_str(), key.c_str(), ToString(size).c_str());
989 }
990
991 array_stack.pop_back();
992}
993
994void Config::SetArrayIndex(const int index) {
995 // You can't set the array index if you haven't started one yet
996 ASSERT(!array_stack.empty());
997
998 const int array_index = index + 1;
999
1000 // You can't exceed the known max size of the array by more than 1
1001 ASSERT(array_stack.front().size + 1 >= array_index);
1002
1003 // Change the config array size to the current index since you may want
1004 // to reduce the number of elements that you read back from the config
1005 // in the future.
1006 array_stack.back().size = array_index;
1007 array_stack.back().index = array_index;
1008}
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <string>
8#include "common/settings.h"
9
10#include <SimpleIni.h>
11#include <boost/algorithm/string/replace.hpp>
12
13// Workaround for conflicting definition in libloaderapi.h caused by SimpleIni
14#undef LoadString
15#undef CreateFile
16#undef DeleteFile
17#undef CopyFile
18#undef CreateDirectory
19#undef MoveFile
20
21namespace Core {
22class System;
23}
24
25class Config {
26public:
27 enum class ConfigType {
28 GlobalConfig,
29 PerGameConfig,
30 InputProfile,
31 };
32
33 virtual ~Config() = default;
34
35 void ClearControlPlayerValues() const;
36
37 [[nodiscard]] const std::string& GetConfigFilePath() const;
38
39 [[nodiscard]] bool Exists(const std::string& section, const std::string& key) const;
40
41protected:
42 explicit Config(ConfigType config_type = ConfigType::GlobalConfig);
43
44 void Initialize(const std::string& config_name = "config");
45 void Initialize(std::optional<std::string> config_path);
46
47 void WriteToIni() const;
48
49 void SetUpIni();
50 [[nodiscard]] bool IsCustomConfig() const;
51
52 void Reload();
53 void Save();
54
55 /**
56 * Derived config classes must implement this so they can reload all platform-specific
57 * values and global ones.
58 */
59 virtual void ReloadAllValues() = 0;
60
61 /**
62 * Derived config classes must implement this so they can save all platform-specific
63 * and global values.
64 */
65 virtual void SaveAllValues() = 0;
66
67 void ReadValues();
68 void ReadPlayerValues(std::size_t player_index);
69
70 void ReadTouchscreenValues();
71 void ReadMotionTouchValues();
72
73 // Read functions bases off the respective config section names.
74 void ReadAudioValues();
75 void ReadControlValues();
76 void ReadCoreValues();
77 void ReadDataStorageValues();
78 void ReadDebuggingValues();
79 void ReadServiceValues();
80 void ReadDisabledAddOnValues();
81 void ReadMiscellaneousValues();
82 void ReadCpuValues();
83 void ReadRendererValues();
84 void ReadScreenshotValues();
85 void ReadSystemValues();
86 void ReadWebServiceValues();
87 void ReadNetworkValues();
88
89 // Read platform specific sections
90 virtual void ReadHidbusValues() = 0;
91 virtual void ReadDebugControlValues() = 0;
92 virtual void ReadPathValues() = 0;
93 virtual void ReadShortcutValues() = 0;
94 virtual void ReadUIValues() = 0;
95 virtual void ReadUIGamelistValues() = 0;
96 virtual void ReadUILayoutValues() = 0;
97 virtual void ReadMultiplayerValues() = 0;
98
99 void SaveValues();
100 void SavePlayerValues(std::size_t player_index);
101 void SaveTouchscreenValues();
102 void SaveMotionTouchValues();
103
104 // Save functions based off the respective config section names.
105 void SaveAudioValues();
106 void SaveControlValues();
107 void SaveCoreValues();
108 void SaveDataStorageValues();
109 void SaveDebuggingValues();
110 void SaveNetworkValues();
111 void SaveDisabledAddOnValues();
112 void SaveMiscellaneousValues();
113 void SaveCpuValues();
114 void SaveRendererValues();
115 void SaveScreenshotValues();
116 void SaveSystemValues();
117 void SaveWebServiceValues();
118
119 // Save platform specific sections
120 virtual void SaveHidbusValues() = 0;
121 virtual void SaveDebugControlValues() = 0;
122 virtual void SavePathValues() = 0;
123 virtual void SaveShortcutValues() = 0;
124 virtual void SaveUIValues() = 0;
125 virtual void SaveUIGamelistValues() = 0;
126 virtual void SaveUILayoutValues() = 0;
127 virtual void SaveMultiplayerValues() = 0;
128
129 virtual std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) = 0;
130
131 /**
132 * Reads a setting from the qt_config.
133 *
134 * @param key The setting's identifier
135 * @param default_value The value to use when the setting is not already present in the config
136 */
137 bool ReadBooleanSetting(const std::string& key,
138 std::optional<bool> default_value = std::nullopt);
139 s64 ReadIntegerSetting(const std::string& key, std::optional<s64> default_value = std::nullopt);
140 u64 ReadUnsignedIntegerSetting(const std::string& key,
141 std::optional<u64> default_value = std::nullopt);
142 double ReadDoubleSetting(const std::string& key,
143 std::optional<double> default_value = std::nullopt);
144 std::string ReadStringSetting(const std::string& key,
145 std::optional<std::string> default_value = std::nullopt);
146
147 /**
148 * Writes a setting to the qt_config.
149 *
150 * @param key The setting's idetentifier
151 * @param value Value of the setting
152 * @param default_value Default of the setting if not present in config
153 * @param use_global Specifies if the custom or global config should be in use, for custom
154 * configs
155 */
156 template <typename Type = int>
157 void WriteSetting(const std::string& key, const Type& value,
158 const std::optional<Type>& default_value = std::nullopt,
159 const std::optional<bool>& use_global = std::nullopt);
160 void WriteSettingInternal(const std::string& key, const std::string& value);
161
162 void ReadCategory(Settings::Category category);
163 void WriteCategory(Settings::Category category);
164 void ReadSettingGeneric(Settings::BasicSetting* setting);
165 void WriteSettingGeneric(const Settings::BasicSetting* setting);
166
167 template <typename T>
168 [[nodiscard]] std::string ToString(const T& value_) {
169 if constexpr (std::is_same_v<T, std::string>) {
170 return value_;
171 } else if constexpr (std::is_same_v<T, std::optional<u32>>) {
172 return value_.has_value() ? std::to_string(*value_) : "none";
173 } else if constexpr (std::is_same_v<T, bool>) {
174 return value_ ? "true" : "false";
175 } else if constexpr (std::is_same_v<T, u64>) {
176 return std::to_string(static_cast<u64>(value_));
177 } else {
178 return std::to_string(static_cast<s64>(value_));
179 }
180 }
181
182 void BeginGroup(const std::string& group);
183 void EndGroup();
184 std::string GetSection();
185 [[nodiscard]] std::string GetGroup() const;
186 static std::string AdjustKey(const std::string& key);
187 static std::string AdjustOutputString(const std::string& string);
188 std::string GetFullKey(const std::string& key, bool skipArrayIndex);
189 int BeginArray(const std::string& array);
190 void EndArray();
191 void SetArrayIndex(int index);
192
193 const ConfigType type;
194 std::unique_ptr<CSimpleIniA> config;
195 std::string config_loc;
196 const bool global;
197
198private:
199 inline static std::array<char, 19> special_characters = {'!', '#', '$', '%', '^', '&', '*',
200 '|', ';', '\'', '\"', ',', '<', '.',
201 '>', '?', '`', '~', '='};
202
203 struct ConfigArray {
204 std::string name;
205 int size;
206 int index;
207 };
208 std::vector<ConfigArray> array_stack;
209 std::vector<std::string> key_stack;
210};
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 @@
4add_subdirectory(host_shaders) 4add_subdirectory(host_shaders)
5 5
6if(LIBVA_FOUND) 6if(LIBVA_FOUND)
7 set_source_files_properties(host1x/codecs/codec.cpp 7 set_source_files_properties(host1x/ffmpeg/ffmpeg.cpp
8 PROPERTIES COMPILE_DEFINITIONS LIBVA_FOUND=1) 8 PROPERTIES COMPILE_DEFINITIONS LIBVA_FOUND=1)
9 list(APPEND FFmpeg_LIBRARIES ${LIBVA_LIBRARIES}) 9 list(APPEND FFmpeg_LIBRARIES ${LIBVA_LIBRARIES})
10endif() 10endif()
@@ -66,6 +66,8 @@ add_library(video_core STATIC
66 host1x/codecs/vp9.cpp 66 host1x/codecs/vp9.cpp
67 host1x/codecs/vp9.h 67 host1x/codecs/vp9.h
68 host1x/codecs/vp9_types.h 68 host1x/codecs/vp9_types.h
69 host1x/ffmpeg/ffmpeg.cpp
70 host1x/ffmpeg/ffmpeg.h
69 host1x/control.cpp 71 host1x/control.cpp
70 host1x/control.h 72 host1x/control.h
71 host1x/host1x.cpp 73 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 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <algorithm>
5#include <fstream>
6#include <vector>
7#include "common/assert.h" 4#include "common/assert.h"
8#include "common/scope_exit.h"
9#include "common/settings.h" 5#include "common/settings.h"
10#include "video_core/host1x/codecs/codec.h" 6#include "video_core/host1x/codecs/codec.h"
11#include "video_core/host1x/codecs/h264.h" 7#include "video_core/host1x/codecs/h264.h"
@@ -14,242 +10,17 @@
14#include "video_core/host1x/host1x.h" 10#include "video_core/host1x/host1x.h"
15#include "video_core/memory_manager.h" 11#include "video_core/memory_manager.h"
16 12
17extern "C" {
18#include <libavfilter/buffersink.h>
19#include <libavfilter/buffersrc.h>
20#include <libavutil/opt.h>
21#ifdef LIBVA_FOUND
22// for querying VAAPI driver information
23#include <libavutil/hwcontext_vaapi.h>
24#endif
25}
26
27namespace Tegra { 13namespace Tegra {
28namespace {
29constexpr AVPixelFormat PREFERRED_GPU_FMT = AV_PIX_FMT_NV12;
30constexpr AVPixelFormat PREFERRED_CPU_FMT = AV_PIX_FMT_YUV420P;
31constexpr std::array PREFERRED_GPU_DECODERS = {
32 AV_HWDEVICE_TYPE_CUDA,
33#ifdef _WIN32
34 AV_HWDEVICE_TYPE_D3D11VA,
35 AV_HWDEVICE_TYPE_DXVA2,
36#elif defined(__unix__)
37 AV_HWDEVICE_TYPE_VAAPI,
38 AV_HWDEVICE_TYPE_VDPAU,
39#endif
40 // last resort for Linux Flatpak (w/ NVIDIA)
41 AV_HWDEVICE_TYPE_VULKAN,
42};
43
44void AVPacketDeleter(AVPacket* ptr) {
45 av_packet_free(&ptr);
46}
47
48using AVPacketPtr = std::unique_ptr<AVPacket, decltype(&AVPacketDeleter)>;
49
50AVPixelFormat GetGpuFormat(AVCodecContext* av_codec_ctx, const AVPixelFormat* pix_fmts) {
51 for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
52 if (*p == av_codec_ctx->pix_fmt) {
53 return av_codec_ctx->pix_fmt;
54 }
55 }
56 LOG_INFO(Service_NVDRV, "Could not find compatible GPU AV format, falling back to CPU");
57 av_buffer_unref(&av_codec_ctx->hw_device_ctx);
58 av_codec_ctx->pix_fmt = PREFERRED_CPU_FMT;
59 return PREFERRED_CPU_FMT;
60}
61
62// List all the currently available hwcontext in ffmpeg
63std::vector<AVHWDeviceType> ListSupportedContexts() {
64 std::vector<AVHWDeviceType> contexts{};
65 AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE;
66 do {
67 current_device_type = av_hwdevice_iterate_types(current_device_type);
68 contexts.push_back(current_device_type);
69 } while (current_device_type != AV_HWDEVICE_TYPE_NONE);
70 return contexts;
71}
72
73} // namespace
74
75void AVFrameDeleter(AVFrame* ptr) {
76 av_frame_free(&ptr);
77}
78 14
79Codec::Codec(Host1x::Host1x& host1x_, const Host1x::NvdecCommon::NvdecRegisters& regs) 15Codec::Codec(Host1x::Host1x& host1x_, const Host1x::NvdecCommon::NvdecRegisters& regs)
80 : host1x(host1x_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(host1x)), 16 : host1x(host1x_), state{regs}, h264_decoder(std::make_unique<Decoder::H264>(host1x)),
81 vp8_decoder(std::make_unique<Decoder::VP8>(host1x)), 17 vp8_decoder(std::make_unique<Decoder::VP8>(host1x)),
82 vp9_decoder(std::make_unique<Decoder::VP9>(host1x)) {} 18 vp9_decoder(std::make_unique<Decoder::VP9>(host1x)) {}
83 19
84Codec::~Codec() { 20Codec::~Codec() = default;
85 if (!initialized) {
86 return;
87 }
88 // Free libav memory
89 avcodec_free_context(&av_codec_ctx);
90 av_buffer_unref(&av_gpu_decoder);
91
92 if (filters_initialized) {
93 avfilter_graph_free(&av_filter_graph);
94 }
95}
96
97bool Codec::CreateGpuAvDevice() {
98 static constexpr auto HW_CONFIG_METHOD = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX;
99 static const auto supported_contexts = ListSupportedContexts();
100 for (const auto& type : PREFERRED_GPU_DECODERS) {
101 if (std::none_of(supported_contexts.begin(), supported_contexts.end(),
102 [&type](const auto& context) { return context == type; })) {
103 LOG_DEBUG(Service_NVDRV, "{} explicitly unsupported", av_hwdevice_get_type_name(type));
104 continue;
105 }
106 // Avoid memory leak from not cleaning up after av_hwdevice_ctx_create
107 av_buffer_unref(&av_gpu_decoder);
108 const int hwdevice_res = av_hwdevice_ctx_create(&av_gpu_decoder, type, nullptr, nullptr, 0);
109 if (hwdevice_res < 0) {
110 LOG_DEBUG(Service_NVDRV, "{} av_hwdevice_ctx_create failed {}",
111 av_hwdevice_get_type_name(type), hwdevice_res);
112 continue;
113 }
114#ifdef LIBVA_FOUND
115 if (type == AV_HWDEVICE_TYPE_VAAPI) {
116 // we need to determine if this is an impersonated VAAPI driver
117 AVHWDeviceContext* hwctx =
118 static_cast<AVHWDeviceContext*>(static_cast<void*>(av_gpu_decoder->data));
119 AVVAAPIDeviceContext* vactx = static_cast<AVVAAPIDeviceContext*>(hwctx->hwctx);
120 const char* vendor_name = vaQueryVendorString(vactx->display);
121 if (strstr(vendor_name, "VDPAU backend")) {
122 // VDPAU impersonated VAAPI impl's are super buggy, we need to skip them
123 LOG_DEBUG(Service_NVDRV, "Skipping vdapu impersonated VAAPI driver");
124 continue;
125 } else {
126 // according to some user testing, certain vaapi driver (Intel?) could be buggy
127 // so let's log the driver name which may help the developers/supporters
128 LOG_DEBUG(Service_NVDRV, "Using VAAPI driver: {}", vendor_name);
129 }
130 }
131#endif
132 for (int i = 0;; i++) {
133 const AVCodecHWConfig* config = avcodec_get_hw_config(av_codec, i);
134 if (!config) {
135 LOG_DEBUG(Service_NVDRV, "{} decoder does not support device type {}.",
136 av_codec->name, av_hwdevice_get_type_name(type));
137 break;
138 }
139 if ((config->methods & HW_CONFIG_METHOD) != 0 && config->device_type == type) {
140 LOG_INFO(Service_NVDRV, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
141 av_codec_ctx->pix_fmt = config->pix_fmt;
142 return true;
143 }
144 }
145 }
146 return false;
147}
148
149void Codec::InitializeAvCodecContext() {
150 av_codec_ctx = avcodec_alloc_context3(av_codec);
151 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
152 av_codec_ctx->thread_count = 0;
153 av_codec_ctx->thread_type &= ~FF_THREAD_FRAME;
154}
155
156void Codec::InitializeGpuDecoder() {
157 if (!CreateGpuAvDevice()) {
158 av_buffer_unref(&av_gpu_decoder);
159 return;
160 }
161 auto* hw_device_ctx = av_buffer_ref(av_gpu_decoder);
162 ASSERT_MSG(hw_device_ctx, "av_buffer_ref failed");
163 av_codec_ctx->hw_device_ctx = hw_device_ctx;
164 av_codec_ctx->get_format = GetGpuFormat;
165}
166
167void Codec::InitializeAvFilters(AVFrame* frame) {
168 const AVFilter* buffer_src = avfilter_get_by_name("buffer");
169 const AVFilter* buffer_sink = avfilter_get_by_name("buffersink");
170 AVFilterInOut* inputs = avfilter_inout_alloc();
171 AVFilterInOut* outputs = avfilter_inout_alloc();
172 SCOPE_EXIT({
173 avfilter_inout_free(&inputs);
174 avfilter_inout_free(&outputs);
175 });
176
177 // Don't know how to get the accurate time_base but it doesn't matter for yadif filter
178 // so just use 1/1 to make buffer filter happy
179 std::string args = fmt::format("video_size={}x{}:pix_fmt={}:time_base=1/1", frame->width,
180 frame->height, frame->format);
181
182 av_filter_graph = avfilter_graph_alloc();
183 int ret = avfilter_graph_create_filter(&av_filter_src_ctx, buffer_src, "in", args.c_str(),
184 nullptr, av_filter_graph);
185 if (ret < 0) {
186 LOG_ERROR(Service_NVDRV, "avfilter_graph_create_filter source error: {}", ret);
187 return;
188 }
189
190 ret = avfilter_graph_create_filter(&av_filter_sink_ctx, buffer_sink, "out", nullptr, nullptr,
191 av_filter_graph);
192 if (ret < 0) {
193 LOG_ERROR(Service_NVDRV, "avfilter_graph_create_filter sink error: {}", ret);
194 return;
195 }
196
197 inputs->name = av_strdup("out");
198 inputs->filter_ctx = av_filter_sink_ctx;
199 inputs->pad_idx = 0;
200 inputs->next = nullptr;
201
202 outputs->name = av_strdup("in");
203 outputs->filter_ctx = av_filter_src_ctx;
204 outputs->pad_idx = 0;
205 outputs->next = nullptr;
206
207 const char* description = "yadif=1:-1:0";
208 ret = avfilter_graph_parse_ptr(av_filter_graph, description, &inputs, &outputs, nullptr);
209 if (ret < 0) {
210 LOG_ERROR(Service_NVDRV, "avfilter_graph_parse_ptr error: {}", ret);
211 return;
212 }
213
214 ret = avfilter_graph_config(av_filter_graph, nullptr);
215 if (ret < 0) {
216 LOG_ERROR(Service_NVDRV, "avfilter_graph_config error: {}", ret);
217 return;
218 }
219
220 filters_initialized = true;
221}
222 21
223void Codec::Initialize() { 22void Codec::Initialize() {
224 const AVCodecID codec = [&] { 23 initialized = decode_api.Initialize(current_codec);
225 switch (current_codec) {
226 case Host1x::NvdecCommon::VideoCodec::H264:
227 return AV_CODEC_ID_H264;
228 case Host1x::NvdecCommon::VideoCodec::VP8:
229 return AV_CODEC_ID_VP8;
230 case Host1x::NvdecCommon::VideoCodec::VP9:
231 return AV_CODEC_ID_VP9;
232 default:
233 UNIMPLEMENTED_MSG("Unknown codec {}", current_codec);
234 return AV_CODEC_ID_NONE;
235 }
236 }();
237 av_codec = avcodec_find_decoder(codec);
238
239 InitializeAvCodecContext();
240 if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) {
241 InitializeGpuDecoder();
242 }
243 if (const int res = avcodec_open2(av_codec_ctx, av_codec, nullptr); res < 0) {
244 LOG_ERROR(Service_NVDRV, "avcodec_open2() Failed with result {}", res);
245 avcodec_free_context(&av_codec_ctx);
246 av_buffer_unref(&av_gpu_decoder);
247 return;
248 }
249 if (!av_codec_ctx->hw_device_ctx) {
250 LOG_INFO(Service_NVDRV, "Using FFmpeg software decoding");
251 }
252 initialized = true;
253} 24}
254 25
255void Codec::SetTargetCodec(Host1x::NvdecCommon::VideoCodec codec) { 26void Codec::SetTargetCodec(Host1x::NvdecCommon::VideoCodec codec) {
@@ -264,14 +35,18 @@ void Codec::Decode() {
264 if (is_first_frame) { 35 if (is_first_frame) {
265 Initialize(); 36 Initialize();
266 } 37 }
38
267 if (!initialized) { 39 if (!initialized) {
268 return; 40 return;
269 } 41 }
42
43 // Assemble bitstream.
270 bool vp9_hidden_frame = false; 44 bool vp9_hidden_frame = false;
271 const auto& frame_data = [&]() { 45 size_t configuration_size = 0;
46 const auto packet_data = [&]() {
272 switch (current_codec) { 47 switch (current_codec) {
273 case Tegra::Host1x::NvdecCommon::VideoCodec::H264: 48 case Tegra::Host1x::NvdecCommon::VideoCodec::H264:
274 return h264_decoder->ComposeFrame(state, is_first_frame); 49 return h264_decoder->ComposeFrame(state, &configuration_size, is_first_frame);
275 case Tegra::Host1x::NvdecCommon::VideoCodec::VP8: 50 case Tegra::Host1x::NvdecCommon::VideoCodec::VP8:
276 return vp8_decoder->ComposeFrame(state); 51 return vp8_decoder->ComposeFrame(state);
277 case Tegra::Host1x::NvdecCommon::VideoCodec::VP9: 52 case Tegra::Host1x::NvdecCommon::VideoCodec::VP9:
@@ -283,89 +58,35 @@ void Codec::Decode() {
283 return std::span<const u8>{}; 58 return std::span<const u8>{};
284 } 59 }
285 }(); 60 }();
286 AVPacketPtr packet{av_packet_alloc(), AVPacketDeleter}; 61
287 if (!packet) { 62 // Send assembled bitstream to decoder.
288 LOG_ERROR(Service_NVDRV, "av_packet_alloc failed"); 63 if (!decode_api.SendPacket(packet_data, configuration_size)) {
289 return;
290 }
291 packet->data = const_cast<u8*>(frame_data.data());
292 packet->size = static_cast<s32>(frame_data.size());
293 if (const int res = avcodec_send_packet(av_codec_ctx, packet.get()); res != 0) {
294 LOG_DEBUG(Service_NVDRV, "avcodec_send_packet error {}", res);
295 return; 64 return;
296 } 65 }
297 // Only receive/store visible frames 66
67 // Only receive/store visible frames.
298 if (vp9_hidden_frame) { 68 if (vp9_hidden_frame) {
299 return; 69 return;
300 } 70 }
301 AVFramePtr initial_frame{av_frame_alloc(), AVFrameDeleter};
302 AVFramePtr final_frame{nullptr, AVFrameDeleter};
303 ASSERT_MSG(initial_frame, "av_frame_alloc initial_frame failed");
304 if (const int ret = avcodec_receive_frame(av_codec_ctx, initial_frame.get()); ret) {
305 LOG_DEBUG(Service_NVDRV, "avcodec_receive_frame error {}", ret);
306 return;
307 }
308 if (initial_frame->width == 0 || initial_frame->height == 0) {
309 LOG_WARNING(Service_NVDRV, "Zero width or height in frame");
310 return;
311 }
312 bool is_interlaced = initial_frame->interlaced_frame != 0;
313 if (av_codec_ctx->hw_device_ctx) {
314 final_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
315 ASSERT_MSG(final_frame, "av_frame_alloc final_frame failed");
316 // Can't use AV_PIX_FMT_YUV420P and share code with software decoding in vic.cpp
317 // because Intel drivers crash unless using AV_PIX_FMT_NV12
318 final_frame->format = PREFERRED_GPU_FMT;
319 const int ret = av_hwframe_transfer_data(final_frame.get(), initial_frame.get(), 0);
320 ASSERT_MSG(!ret, "av_hwframe_transfer_data error {}", ret);
321 } else {
322 final_frame = std::move(initial_frame);
323 }
324 if (final_frame->format != PREFERRED_CPU_FMT && final_frame->format != PREFERRED_GPU_FMT) {
325 UNIMPLEMENTED_MSG("Unexpected video format: {}", final_frame->format);
326 return;
327 }
328 if (!is_interlaced) {
329 av_frames.push(std::move(final_frame));
330 } else {
331 if (!filters_initialized) {
332 InitializeAvFilters(final_frame.get());
333 }
334 if (const int ret = av_buffersrc_add_frame_flags(av_filter_src_ctx, final_frame.get(),
335 AV_BUFFERSRC_FLAG_KEEP_REF);
336 ret) {
337 LOG_DEBUG(Service_NVDRV, "av_buffersrc_add_frame_flags error {}", ret);
338 return;
339 }
340 while (true) {
341 auto filter_frame = AVFramePtr{av_frame_alloc(), AVFrameDeleter};
342 71
343 int ret = av_buffersink_get_frame(av_filter_sink_ctx, filter_frame.get()); 72 // Receive output frames from decoder.
73 decode_api.ReceiveFrames(frames);
344 74
345 if (ret == AVERROR(EAGAIN) || ret == AVERROR(AVERROR_EOF)) 75 while (frames.size() > 10) {
346 break; 76 LOG_DEBUG(HW_GPU, "ReceiveFrames overflow, dropped frame");
347 if (ret < 0) { 77 frames.pop();
348 LOG_DEBUG(Service_NVDRV, "av_buffersink_get_frame error {}", ret);
349 return;
350 }
351
352 av_frames.push(std::move(filter_frame));
353 }
354 }
355 while (av_frames.size() > 10) {
356 LOG_TRACE(Service_NVDRV, "av_frames.push overflow dropped frame");
357 av_frames.pop();
358 } 78 }
359} 79}
360 80
361AVFramePtr Codec::GetCurrentFrame() { 81std::unique_ptr<FFmpeg::Frame> Codec::GetCurrentFrame() {
362 // Sometimes VIC will request more frames than have been decoded. 82 // Sometimes VIC will request more frames than have been decoded.
363 // in this case, return a nullptr and don't overwrite previous frame data 83 // in this case, return a blank frame and don't overwrite previous data.
364 if (av_frames.empty()) { 84 if (frames.empty()) {
365 return AVFramePtr{nullptr, AVFrameDeleter}; 85 return {};
366 } 86 }
367 AVFramePtr frame = std::move(av_frames.front()); 87
368 av_frames.pop(); 88 auto frame = std::move(frames.front());
89 frames.pop();
369 return frame; 90 return frame;
370} 91}
371 92
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 @@
4#pragma once 4#pragma once
5 5
6#include <memory> 6#include <memory>
7#include <optional>
7#include <string_view> 8#include <string_view>
8#include <queue> 9#include <queue>
9#include "common/common_types.h" 10#include "common/common_types.h"
11#include "video_core/host1x/ffmpeg/ffmpeg.h"
10#include "video_core/host1x/nvdec_common.h" 12#include "video_core/host1x/nvdec_common.h"
11 13
12extern "C" {
13#if defined(__GNUC__) || defined(__clang__)
14#pragma GCC diagnostic push
15#pragma GCC diagnostic ignored "-Wconversion"
16#endif
17#include <libavcodec/avcodec.h>
18#include <libavfilter/avfilter.h>
19#if defined(__GNUC__) || defined(__clang__)
20#pragma GCC diagnostic pop
21#endif
22}
23
24namespace Tegra { 14namespace Tegra {
25 15
26void AVFrameDeleter(AVFrame* ptr);
27using AVFramePtr = std::unique_ptr<AVFrame, decltype(&AVFrameDeleter)>;
28
29namespace Decoder { 16namespace Decoder {
30class H264; 17class H264;
31class VP8; 18class VP8;
@@ -51,7 +38,7 @@ public:
51 void Decode(); 38 void Decode();
52 39
53 /// Returns next decoded frame 40 /// Returns next decoded frame
54 [[nodiscard]] AVFramePtr GetCurrentFrame(); 41 [[nodiscard]] std::unique_ptr<FFmpeg::Frame> GetCurrentFrame();
55 42
56 /// Returns the value of current_codec 43 /// Returns the value of current_codec
57 [[nodiscard]] Host1x::NvdecCommon::VideoCodec GetCurrentCodec() const; 44 [[nodiscard]] Host1x::NvdecCommon::VideoCodec GetCurrentCodec() const;
@@ -60,25 +47,9 @@ public:
60 [[nodiscard]] std::string_view GetCurrentCodecName() const; 47 [[nodiscard]] std::string_view GetCurrentCodecName() const;
61 48
62private: 49private:
63 void InitializeAvCodecContext();
64
65 void InitializeAvFilters(AVFrame* frame);
66
67 void InitializeGpuDecoder();
68
69 bool CreateGpuAvDevice();
70
71 bool initialized{}; 50 bool initialized{};
72 bool filters_initialized{};
73 Host1x::NvdecCommon::VideoCodec current_codec{Host1x::NvdecCommon::VideoCodec::None}; 51 Host1x::NvdecCommon::VideoCodec current_codec{Host1x::NvdecCommon::VideoCodec::None};
74 52 FFmpeg::DecodeApi decode_api;
75 const AVCodec* av_codec{nullptr};
76 AVCodecContext* av_codec_ctx{nullptr};
77 AVBufferRef* av_gpu_decoder{nullptr};
78
79 AVFilterContext* av_filter_src_ctx{nullptr};
80 AVFilterContext* av_filter_sink_ctx{nullptr};
81 AVFilterGraph* av_filter_graph{nullptr};
82 53
83 Host1x::Host1x& host1x; 54 Host1x::Host1x& host1x;
84 const Host1x::NvdecCommon::NvdecRegisters& state; 55 const Host1x::NvdecCommon::NvdecRegisters& state;
@@ -86,7 +57,7 @@ private:
86 std::unique_ptr<Decoder::VP8> vp8_decoder; 57 std::unique_ptr<Decoder::VP8> vp8_decoder;
87 std::unique_ptr<Decoder::VP9> vp9_decoder; 58 std::unique_ptr<Decoder::VP9> vp9_decoder;
88 59
89 std::queue<AVFramePtr> av_frames{}; 60 std::queue<std::unique_ptr<FFmpeg::Frame>> frames{};
90}; 61};
91 62
92} // namespace Tegra 63} // 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_} {}
30H264::~H264() = default; 30H264::~H264() = default;
31 31
32std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state, 32std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
33 bool is_first_frame) { 33 size_t* out_configuration_size, bool is_first_frame) {
34 H264DecoderContext context; 34 H264DecoderContext context;
35 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &context, 35 host1x.MemoryManager().ReadBlock(state.picture_info_offset, &context,
36 sizeof(H264DecoderContext)); 36 sizeof(H264DecoderContext));
@@ -39,6 +39,7 @@ std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters
39 if (!is_first_frame && frame_number != 0) { 39 if (!is_first_frame && frame_number != 0) {
40 frame.resize_destructive(context.stream_len); 40 frame.resize_destructive(context.stream_len);
41 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size()); 41 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, frame.data(), frame.size());
42 *out_configuration_size = 0;
42 return frame; 43 return frame;
43 } 44 }
44 45
@@ -157,6 +158,7 @@ std::span<const u8> H264::ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters
157 frame.resize(encoded_header.size() + context.stream_len); 158 frame.resize(encoded_header.size() + context.stream_len);
158 std::memcpy(frame.data(), encoded_header.data(), encoded_header.size()); 159 std::memcpy(frame.data(), encoded_header.data(), encoded_header.size());
159 160
161 *out_configuration_size = encoded_header.size();
160 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset, 162 host1x.MemoryManager().ReadBlock(state.frame_bitstream_offset,
161 frame.data() + encoded_header.size(), context.stream_len); 163 frame.data() + encoded_header.size(), context.stream_len);
162 164
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:
67 67
68 /// Compose the H264 frame for FFmpeg decoding 68 /// Compose the H264 frame for FFmpeg decoding
69 [[nodiscard]] std::span<const u8> ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state, 69 [[nodiscard]] std::span<const u8> ComposeFrame(const Host1x::NvdecCommon::NvdecRegisters& state,
70 size_t* out_configuration_size,
70 bool is_first_frame = false); 71 bool is_first_frame = false);
71 72
72private: 73private:
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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/assert.h"
5#include "common/logging/log.h"
6#include "common/scope_exit.h"
7#include "common/settings.h"
8#include "video_core/host1x/ffmpeg/ffmpeg.h"
9
10extern "C" {
11#ifdef LIBVA_FOUND
12// for querying VAAPI driver information
13#include <libavutil/hwcontext_vaapi.h>
14#endif
15}
16
17namespace FFmpeg {
18
19namespace {
20
21constexpr AVPixelFormat PreferredGpuFormat = AV_PIX_FMT_NV12;
22constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P;
23constexpr std::array PreferredGpuDecoders = {
24 AV_HWDEVICE_TYPE_CUDA,
25#ifdef _WIN32
26 AV_HWDEVICE_TYPE_D3D11VA,
27 AV_HWDEVICE_TYPE_DXVA2,
28#elif defined(__unix__)
29 AV_HWDEVICE_TYPE_VAAPI,
30 AV_HWDEVICE_TYPE_VDPAU,
31#endif
32 // last resort for Linux Flatpak (w/ NVIDIA)
33 AV_HWDEVICE_TYPE_VULKAN,
34};
35
36AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* pix_fmts) {
37 for (const AVPixelFormat* p = pix_fmts; *p != AV_PIX_FMT_NONE; ++p) {
38 if (*p == codec_context->pix_fmt) {
39 return codec_context->pix_fmt;
40 }
41 }
42
43 LOG_INFO(HW_GPU, "Could not find compatible GPU AV format, falling back to CPU");
44 av_buffer_unref(&codec_context->hw_device_ctx);
45
46 codec_context->pix_fmt = PreferredCpuFormat;
47 return codec_context->pix_fmt;
48}
49
50std::string AVError(int errnum) {
51 char errbuf[AV_ERROR_MAX_STRING_SIZE] = {};
52 av_make_error_string(errbuf, sizeof(errbuf) - 1, errnum);
53 return errbuf;
54}
55
56} // namespace
57
58Packet::Packet(std::span<const u8> data) {
59 m_packet = av_packet_alloc();
60 m_packet->data = const_cast<u8*>(data.data());
61 m_packet->size = static_cast<s32>(data.size());
62}
63
64Packet::~Packet() {
65 av_packet_free(&m_packet);
66}
67
68Frame::Frame() {
69 m_frame = av_frame_alloc();
70}
71
72Frame::~Frame() {
73 av_frame_free(&m_frame);
74}
75
76Decoder::Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec) {
77 const AVCodecID av_codec = [&] {
78 switch (codec) {
79 case Tegra::Host1x::NvdecCommon::VideoCodec::H264:
80 return AV_CODEC_ID_H264;
81 case Tegra::Host1x::NvdecCommon::VideoCodec::VP8:
82 return AV_CODEC_ID_VP8;
83 case Tegra::Host1x::NvdecCommon::VideoCodec::VP9:
84 return AV_CODEC_ID_VP9;
85 default:
86 UNIMPLEMENTED_MSG("Unknown codec {}", codec);
87 return AV_CODEC_ID_NONE;
88 }
89 }();
90
91 m_codec = avcodec_find_decoder(av_codec);
92}
93
94bool Decoder::SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceType type) const {
95 for (int i = 0;; i++) {
96 const AVCodecHWConfig* config = avcodec_get_hw_config(m_codec, i);
97 if (!config) {
98 LOG_DEBUG(HW_GPU, "{} decoder does not support device type {}", m_codec->name,
99 av_hwdevice_get_type_name(type));
100 break;
101 }
102 if ((config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) != 0 &&
103 config->device_type == type) {
104 LOG_INFO(HW_GPU, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
105 *out_pix_fmt = config->pix_fmt;
106 return true;
107 }
108 }
109
110 return false;
111}
112
113std::vector<AVHWDeviceType> HardwareContext::GetSupportedDeviceTypes() {
114 std::vector<AVHWDeviceType> types;
115 AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE;
116
117 while (true) {
118 current_device_type = av_hwdevice_iterate_types(current_device_type);
119 if (current_device_type == AV_HWDEVICE_TYPE_NONE) {
120 return types;
121 }
122
123 types.push_back(current_device_type);
124 }
125}
126
127HardwareContext::~HardwareContext() {
128 av_buffer_unref(&m_gpu_decoder);
129}
130
131bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context,
132 const Decoder& decoder) {
133 const auto supported_types = GetSupportedDeviceTypes();
134 for (const auto type : PreferredGpuDecoders) {
135 AVPixelFormat hw_pix_fmt;
136
137 if (std::ranges::find(supported_types, type) == supported_types.end()) {
138 LOG_DEBUG(HW_GPU, "{} explicitly unsupported", av_hwdevice_get_type_name(type));
139 continue;
140 }
141
142 if (!this->InitializeWithType(type)) {
143 continue;
144 }
145
146 if (decoder.SupportsDecodingOnDevice(&hw_pix_fmt, type)) {
147 decoder_context.InitializeHardwareDecoder(*this, hw_pix_fmt);
148 return true;
149 }
150 }
151
152 return false;
153}
154
155bool HardwareContext::InitializeWithType(AVHWDeviceType type) {
156 av_buffer_unref(&m_gpu_decoder);
157
158 if (const int ret = av_hwdevice_ctx_create(&m_gpu_decoder, type, nullptr, nullptr, 0);
159 ret < 0) {
160 LOG_DEBUG(HW_GPU, "av_hwdevice_ctx_create({}) failed: {}", av_hwdevice_get_type_name(type),
161 AVError(ret));
162 return false;
163 }
164
165#ifdef LIBVA_FOUND
166 if (type == AV_HWDEVICE_TYPE_VAAPI) {
167 // We need to determine if this is an impersonated VAAPI driver.
168 auto* hwctx = reinterpret_cast<AVHWDeviceContext*>(m_gpu_decoder->data);
169 auto* vactx = static_cast<AVVAAPIDeviceContext*>(hwctx->hwctx);
170 const char* vendor_name = vaQueryVendorString(vactx->display);
171 if (strstr(vendor_name, "VDPAU backend")) {
172 // VDPAU impersonated VAAPI impls are super buggy, we need to skip them.
173 LOG_DEBUG(HW_GPU, "Skipping VDPAU impersonated VAAPI driver");
174 return false;
175 } else {
176 // According to some user testing, certain VAAPI drivers (Intel?) could be buggy.
177 // Log the driver name just in case.
178 LOG_DEBUG(HW_GPU, "Using VAAPI driver: {}", vendor_name);
179 }
180 }
181#endif
182
183 return true;
184}
185
186DecoderContext::DecoderContext(const Decoder& decoder) {
187 m_codec_context = avcodec_alloc_context3(decoder.GetCodec());
188 av_opt_set(m_codec_context->priv_data, "tune", "zerolatency", 0);
189 m_codec_context->thread_count = 0;
190 m_codec_context->thread_type &= ~FF_THREAD_FRAME;
191}
192
193DecoderContext::~DecoderContext() {
194 av_buffer_unref(&m_codec_context->hw_device_ctx);
195 avcodec_free_context(&m_codec_context);
196}
197
198void DecoderContext::InitializeHardwareDecoder(const HardwareContext& context,
199 AVPixelFormat hw_pix_fmt) {
200 m_codec_context->hw_device_ctx = av_buffer_ref(context.GetBufferRef());
201 m_codec_context->get_format = GetGpuFormat;
202 m_codec_context->pix_fmt = hw_pix_fmt;
203}
204
205bool DecoderContext::OpenContext(const Decoder& decoder) {
206 if (const int ret = avcodec_open2(m_codec_context, decoder.GetCodec(), nullptr); ret < 0) {
207 LOG_ERROR(HW_GPU, "avcodec_open2 error: {}", AVError(ret));
208 return false;
209 }
210
211 if (!m_codec_context->hw_device_ctx) {
212 LOG_INFO(HW_GPU, "Using FFmpeg software decoding");
213 }
214
215 return true;
216}
217
218bool DecoderContext::SendPacket(const Packet& packet) {
219 if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0) {
220 LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret));
221 return false;
222 }
223
224 return true;
225}
226
227std::unique_ptr<Frame> DecoderContext::ReceiveFrame(bool* out_is_interlaced) {
228 auto dst_frame = std::make_unique<Frame>();
229
230 const auto ReceiveImpl = [&](AVFrame* frame) {
231 if (const int ret = avcodec_receive_frame(m_codec_context, frame); ret < 0) {
232 LOG_ERROR(HW_GPU, "avcodec_receive_frame error: {}", AVError(ret));
233 return false;
234 }
235
236 *out_is_interlaced = frame->interlaced_frame != 0;
237 return true;
238 };
239
240 if (m_codec_context->hw_device_ctx) {
241 // If we have a hardware context, make a separate frame here to receive the
242 // hardware result before sending it to the output.
243 Frame intermediate_frame;
244
245 if (!ReceiveImpl(intermediate_frame.GetFrame())) {
246 return {};
247 }
248
249 dst_frame->SetFormat(PreferredGpuFormat);
250 if (const int ret =
251 av_hwframe_transfer_data(dst_frame->GetFrame(), intermediate_frame.GetFrame(), 0);
252 ret < 0) {
253 LOG_ERROR(HW_GPU, "av_hwframe_transfer_data error: {}", AVError(ret));
254 return {};
255 }
256 } else {
257 // Otherwise, decode the frame as normal.
258 if (!ReceiveImpl(dst_frame->GetFrame())) {
259 return {};
260 }
261 }
262
263 return dst_frame;
264}
265
266DeinterlaceFilter::DeinterlaceFilter(const Frame& frame) {
267 const AVFilter* buffer_src = avfilter_get_by_name("buffer");
268 const AVFilter* buffer_sink = avfilter_get_by_name("buffersink");
269 AVFilterInOut* inputs = avfilter_inout_alloc();
270 AVFilterInOut* outputs = avfilter_inout_alloc();
271 SCOPE_EXIT({
272 avfilter_inout_free(&inputs);
273 avfilter_inout_free(&outputs);
274 });
275
276 // Don't know how to get the accurate time_base but it doesn't matter for yadif filter
277 // so just use 1/1 to make buffer filter happy
278 std::string args = fmt::format("video_size={}x{}:pix_fmt={}:time_base=1/1", frame.GetWidth(),
279 frame.GetHeight(), static_cast<int>(frame.GetPixelFormat()));
280
281 m_filter_graph = avfilter_graph_alloc();
282 int ret = avfilter_graph_create_filter(&m_source_context, buffer_src, "in", args.c_str(),
283 nullptr, m_filter_graph);
284 if (ret < 0) {
285 LOG_ERROR(HW_GPU, "avfilter_graph_create_filter source error: {}", AVError(ret));
286 return;
287 }
288
289 ret = avfilter_graph_create_filter(&m_sink_context, buffer_sink, "out", nullptr, nullptr,
290 m_filter_graph);
291 if (ret < 0) {
292 LOG_ERROR(HW_GPU, "avfilter_graph_create_filter sink error: {}", AVError(ret));
293 return;
294 }
295
296 inputs->name = av_strdup("out");
297 inputs->filter_ctx = m_sink_context;
298 inputs->pad_idx = 0;
299 inputs->next = nullptr;
300
301 outputs->name = av_strdup("in");
302 outputs->filter_ctx = m_source_context;
303 outputs->pad_idx = 0;
304 outputs->next = nullptr;
305
306 const char* description = "yadif=1:-1:0";
307 ret = avfilter_graph_parse_ptr(m_filter_graph, description, &inputs, &outputs, nullptr);
308 if (ret < 0) {
309 LOG_ERROR(HW_GPU, "avfilter_graph_parse_ptr error: {}", AVError(ret));
310 return;
311 }
312
313 ret = avfilter_graph_config(m_filter_graph, nullptr);
314 if (ret < 0) {
315 LOG_ERROR(HW_GPU, "avfilter_graph_config error: {}", AVError(ret));
316 return;
317 }
318
319 m_initialized = true;
320}
321
322bool DeinterlaceFilter::AddSourceFrame(const Frame& frame) {
323 if (const int ret = av_buffersrc_add_frame_flags(m_source_context, frame.GetFrame(),
324 AV_BUFFERSRC_FLAG_KEEP_REF);
325 ret < 0) {
326 LOG_ERROR(HW_GPU, "av_buffersrc_add_frame_flags error: {}", AVError(ret));
327 return false;
328 }
329
330 return true;
331}
332
333std::unique_ptr<Frame> DeinterlaceFilter::DrainSinkFrame() {
334 auto dst_frame = std::make_unique<Frame>();
335 const int ret = av_buffersink_get_frame(m_sink_context, dst_frame->GetFrame());
336
337 if (ret == AVERROR(EAGAIN) || ret == AVERROR(AVERROR_EOF)) {
338 return {};
339 }
340
341 if (ret < 0) {
342 LOG_ERROR(HW_GPU, "av_buffersink_get_frame error: {}", AVError(ret));
343 return {};
344 }
345
346 return dst_frame;
347}
348
349DeinterlaceFilter::~DeinterlaceFilter() {
350 avfilter_graph_free(&m_filter_graph);
351}
352
353void DecodeApi::Reset() {
354 m_deinterlace_filter.reset();
355 m_hardware_context.reset();
356 m_decoder_context.reset();
357 m_decoder.reset();
358}
359
360bool DecodeApi::Initialize(Tegra::Host1x::NvdecCommon::VideoCodec codec) {
361 this->Reset();
362 m_decoder.emplace(codec);
363 m_decoder_context.emplace(*m_decoder);
364
365 // Enable GPU decoding if requested.
366 if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) {
367 m_hardware_context.emplace();
368 m_hardware_context->InitializeForDecoder(*m_decoder_context, *m_decoder);
369 }
370
371 // Open the decoder context.
372 if (!m_decoder_context->OpenContext(*m_decoder)) {
373 this->Reset();
374 return false;
375 }
376
377 return true;
378}
379
380bool DecodeApi::SendPacket(std::span<const u8> packet_data, size_t configuration_size) {
381 FFmpeg::Packet packet(packet_data);
382 return m_decoder_context->SendPacket(packet);
383}
384
385void DecodeApi::ReceiveFrames(std::queue<std::unique_ptr<Frame>>& frame_queue) {
386 // Receive raw frame from decoder.
387 bool is_interlaced;
388 auto frame = m_decoder_context->ReceiveFrame(&is_interlaced);
389 if (!frame) {
390 return;
391 }
392
393 if (!is_interlaced) {
394 // If the frame is not interlaced, we can pend it now.
395 frame_queue.push(std::move(frame));
396 } else {
397 // Create the deinterlacer if needed.
398 if (!m_deinterlace_filter) {
399 m_deinterlace_filter.emplace(*frame);
400 }
401
402 // Add the frame we just received.
403 if (!m_deinterlace_filter->AddSourceFrame(*frame)) {
404 return;
405 }
406
407 // Pend output fields.
408 while (true) {
409 auto filter_frame = m_deinterlace_filter->DrainSinkFrame();
410 if (!filter_frame) {
411 break;
412 }
413
414 frame_queue.push(std::move(filter_frame));
415 }
416 }
417}
418
419} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <optional>
8#include <span>
9#include <vector>
10#include <queue>
11
12#include "common/common_funcs.h"
13#include "common/common_types.h"
14#include "video_core/host1x/nvdec_common.h"
15
16extern "C" {
17#if defined(__GNUC__) || defined(__clang__)
18#pragma GCC diagnostic push
19#pragma GCC diagnostic ignored "-Wconversion"
20#endif
21
22#include <libavcodec/avcodec.h>
23#include <libavfilter/avfilter.h>
24#include <libavfilter/buffersink.h>
25#include <libavfilter/buffersrc.h>
26#include <libavutil/avutil.h>
27#include <libavutil/opt.h>
28
29#if defined(__GNUC__) || defined(__clang__)
30#pragma GCC diagnostic pop
31#endif
32}
33
34namespace FFmpeg {
35
36class Packet;
37class Frame;
38class Decoder;
39class HardwareContext;
40class DecoderContext;
41class DeinterlaceFilter;
42
43// Wraps an AVPacket, a container for compressed bitstream data.
44class Packet {
45public:
46 YUZU_NON_COPYABLE(Packet);
47 YUZU_NON_MOVEABLE(Packet);
48
49 explicit Packet(std::span<const u8> data);
50 ~Packet();
51
52 AVPacket* GetPacket() const {
53 return m_packet;
54 }
55
56private:
57 AVPacket* m_packet{};
58};
59
60// Wraps an AVFrame, a container for audio and video stream data.
61class Frame {
62public:
63 YUZU_NON_COPYABLE(Frame);
64 YUZU_NON_MOVEABLE(Frame);
65
66 explicit Frame();
67 ~Frame();
68
69 int GetWidth() const {
70 return m_frame->width;
71 }
72
73 int GetHeight() const {
74 return m_frame->height;
75 }
76
77 AVPixelFormat GetPixelFormat() const {
78 return static_cast<AVPixelFormat>(m_frame->format);
79 }
80
81 int GetStride(int plane) const {
82 return m_frame->linesize[plane];
83 }
84
85 int* GetStrides() const {
86 return m_frame->linesize;
87 }
88
89 u8* GetData(int plane) const {
90 return m_frame->data[plane];
91 }
92
93 u8** GetPlanes() const {
94 return m_frame->data;
95 }
96
97 void SetFormat(int format) {
98 m_frame->format = format;
99 }
100
101 AVFrame* GetFrame() const {
102 return m_frame;
103 }
104
105private:
106 AVFrame* m_frame{};
107};
108
109// Wraps an AVCodec, a type containing information about a codec.
110class Decoder {
111public:
112 YUZU_NON_COPYABLE(Decoder);
113 YUZU_NON_MOVEABLE(Decoder);
114
115 explicit Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec);
116 ~Decoder() = default;
117
118 bool SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceType type) const;
119
120 const AVCodec* GetCodec() const {
121 return m_codec;
122 }
123
124private:
125 const AVCodec* m_codec{};
126};
127
128// Wraps AVBufferRef for an accelerated decoder.
129class HardwareContext {
130public:
131 YUZU_NON_COPYABLE(HardwareContext);
132 YUZU_NON_MOVEABLE(HardwareContext);
133
134 static std::vector<AVHWDeviceType> GetSupportedDeviceTypes();
135
136 explicit HardwareContext() = default;
137 ~HardwareContext();
138
139 bool InitializeForDecoder(DecoderContext& decoder_context, const Decoder& decoder);
140
141 AVBufferRef* GetBufferRef() const {
142 return m_gpu_decoder;
143 }
144
145private:
146 bool InitializeWithType(AVHWDeviceType type);
147
148 AVBufferRef* m_gpu_decoder{};
149};
150
151// Wraps an AVCodecContext.
152class DecoderContext {
153public:
154 YUZU_NON_COPYABLE(DecoderContext);
155 YUZU_NON_MOVEABLE(DecoderContext);
156
157 explicit DecoderContext(const Decoder& decoder);
158 ~DecoderContext();
159
160 void InitializeHardwareDecoder(const HardwareContext& context, AVPixelFormat hw_pix_fmt);
161 bool OpenContext(const Decoder& decoder);
162 bool SendPacket(const Packet& packet);
163 std::unique_ptr<Frame> ReceiveFrame(bool* out_is_interlaced);
164
165 AVCodecContext* GetCodecContext() const {
166 return m_codec_context;
167 }
168
169private:
170 AVCodecContext* m_codec_context{};
171};
172
173// Wraps an AVFilterGraph.
174class DeinterlaceFilter {
175public:
176 YUZU_NON_COPYABLE(DeinterlaceFilter);
177 YUZU_NON_MOVEABLE(DeinterlaceFilter);
178
179 explicit DeinterlaceFilter(const Frame& frame);
180 ~DeinterlaceFilter();
181
182 bool AddSourceFrame(const Frame& frame);
183 std::unique_ptr<Frame> DrainSinkFrame();
184
185private:
186 AVFilterGraph* m_filter_graph{};
187 AVFilterContext* m_source_context{};
188 AVFilterContext* m_sink_context{};
189 bool m_initialized{};
190};
191
192class DecodeApi {
193public:
194 YUZU_NON_COPYABLE(DecodeApi);
195 YUZU_NON_MOVEABLE(DecodeApi);
196
197 DecodeApi() = default;
198 ~DecodeApi() = default;
199
200 bool Initialize(Tegra::Host1x::NvdecCommon::VideoCodec codec);
201 void Reset();
202
203 bool SendPacket(std::span<const u8> packet_data, size_t configuration_size);
204 void ReceiveFrames(std::queue<std::unique_ptr<Frame>>& frame_queue);
205
206private:
207 std::optional<FFmpeg::Decoder> m_decoder;
208 std::optional<FFmpeg::DecoderContext> m_decoder_context;
209 std::optional<FFmpeg::HardwareContext> m_hardware_context;
210 std::optional<FFmpeg::DeinterlaceFilter> m_deinterlace_filter;
211};
212
213} // 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) {
28 } 28 }
29} 29}
30 30
31AVFramePtr Nvdec::GetFrame() { 31std::unique_ptr<FFmpeg::Frame> Nvdec::GetFrame() {
32 return codec->GetCurrentFrame(); 32 return codec->GetCurrentFrame();
33} 33}
34 34
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:
23 void ProcessMethod(u32 method, u32 argument); 23 void ProcessMethod(u32 method, u32 argument);
24 24
25 /// Return most recently decoded frame 25 /// Return most recently decoded frame
26 [[nodiscard]] AVFramePtr GetFrame(); 26 [[nodiscard]] std::unique_ptr<FFmpeg::Frame> GetFrame();
27 27
28private: 28private:
29 /// Invoke codec to decode a frame 29 /// 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() {
82 return; 82 return;
83 } 83 }
84 const VicConfig config{host1x.MemoryManager().Read<u64>(config_struct_address + 0x20)}; 84 const VicConfig config{host1x.MemoryManager().Read<u64>(config_struct_address + 0x20)};
85 const AVFramePtr frame_ptr = nvdec_processor->GetFrame(); 85 auto frame = nvdec_processor->GetFrame();
86 const auto* frame = frame_ptr.get();
87 if (!frame) { 86 if (!frame) {
88 return; 87 return;
89 } 88 }
90 const u64 surface_width = config.surface_width_minus1 + 1; 89 const u64 surface_width = config.surface_width_minus1 + 1;
91 const u64 surface_height = config.surface_height_minus1 + 1; 90 const u64 surface_height = config.surface_height_minus1 + 1;
92 if (static_cast<u64>(frame->width) != surface_width || 91 if (static_cast<u64>(frame->GetWidth()) != surface_width ||
93 static_cast<u64>(frame->height) != surface_height) { 92 static_cast<u64>(frame->GetHeight()) != surface_height) {
94 // TODO: Properly support multiple video streams with differing frame dimensions 93 // TODO: Properly support multiple video streams with differing frame dimensions
95 LOG_WARNING(Service_NVDRV, "Frame dimensions {}x{} don't match surface dimensions {}x{}", 94 LOG_WARNING(Service_NVDRV, "Frame dimensions {}x{} don't match surface dimensions {}x{}",
96 frame->width, frame->height, surface_width, surface_height); 95 frame->GetWidth(), frame->GetHeight(), surface_width, surface_height);
97 } 96 }
98 switch (config.pixel_format) { 97 switch (config.pixel_format) {
99 case VideoPixelFormat::RGBA8: 98 case VideoPixelFormat::RGBA8:
100 case VideoPixelFormat::BGRA8: 99 case VideoPixelFormat::BGRA8:
101 case VideoPixelFormat::RGBX8: 100 case VideoPixelFormat::RGBX8:
102 WriteRGBFrame(frame, config); 101 WriteRGBFrame(std::move(frame), config);
103 break; 102 break;
104 case VideoPixelFormat::YUV420: 103 case VideoPixelFormat::YUV420:
105 WriteYUVFrame(frame, config); 104 WriteYUVFrame(std::move(frame), config);
106 break; 105 break;
107 default: 106 default:
108 UNIMPLEMENTED_MSG("Unknown video pixel format {:X}", config.pixel_format.Value()); 107 UNIMPLEMENTED_MSG("Unknown video pixel format {:X}", config.pixel_format.Value());
@@ -110,10 +109,14 @@ void Vic::Execute() {
110 } 109 }
111} 110}
112 111
113void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) { 112void Vic::WriteRGBFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& config) {
114 LOG_TRACE(Service_NVDRV, "Writing RGB Frame"); 113 LOG_TRACE(Service_NVDRV, "Writing RGB Frame");
115 114
116 if (!scaler_ctx || frame->width != scaler_width || frame->height != scaler_height) { 115 const auto frame_width = frame->GetWidth();
116 const auto frame_height = frame->GetHeight();
117 const auto frame_format = frame->GetPixelFormat();
118
119 if (!scaler_ctx || frame_width != scaler_width || frame_height != scaler_height) {
117 const AVPixelFormat target_format = [pixel_format = config.pixel_format]() { 120 const AVPixelFormat target_format = [pixel_format = config.pixel_format]() {
118 switch (pixel_format) { 121 switch (pixel_format) {
119 case VideoPixelFormat::RGBA8: 122 case VideoPixelFormat::RGBA8:
@@ -129,27 +132,26 @@ void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) {
129 132
130 sws_freeContext(scaler_ctx); 133 sws_freeContext(scaler_ctx);
131 // Frames are decoded into either YUV420 or NV12 formats. Convert to desired RGB format 134 // Frames are decoded into either YUV420 or NV12 formats. Convert to desired RGB format
132 scaler_ctx = sws_getContext(frame->width, frame->height, 135 scaler_ctx = sws_getContext(frame_width, frame_height, frame_format, frame_width,
133 static_cast<AVPixelFormat>(frame->format), frame->width, 136 frame_height, target_format, 0, nullptr, nullptr, nullptr);
134 frame->height, target_format, 0, nullptr, nullptr, nullptr); 137 scaler_width = frame_width;
135 scaler_width = frame->width; 138 scaler_height = frame_height;
136 scaler_height = frame->height;
137 converted_frame_buffer.reset(); 139 converted_frame_buffer.reset();
138 } 140 }
139 if (!converted_frame_buffer) { 141 if (!converted_frame_buffer) {
140 const size_t frame_size = frame->width * frame->height * 4; 142 const size_t frame_size = frame_width * frame_height * 4;
141 converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(frame_size)), av_free}; 143 converted_frame_buffer = AVMallocPtr{static_cast<u8*>(av_malloc(frame_size)), av_free};
142 } 144 }
143 const std::array<int, 4> converted_stride{frame->width * 4, frame->height * 4, 0, 0}; 145 const std::array<int, 4> converted_stride{frame_width * 4, frame_height * 4, 0, 0};
144 u8* const converted_frame_buf_addr{converted_frame_buffer.get()}; 146 u8* const converted_frame_buf_addr{converted_frame_buffer.get()};
145 sws_scale(scaler_ctx, frame->data, frame->linesize, 0, frame->height, &converted_frame_buf_addr, 147 sws_scale(scaler_ctx, frame->GetPlanes(), frame->GetStrides(), 0, frame_height,
146 converted_stride.data()); 148 &converted_frame_buf_addr, converted_stride.data());
147 149
148 // Use the minimum of surface/frame dimensions to avoid buffer overflow. 150 // Use the minimum of surface/frame dimensions to avoid buffer overflow.
149 const u32 surface_width = static_cast<u32>(config.surface_width_minus1) + 1; 151 const u32 surface_width = static_cast<u32>(config.surface_width_minus1) + 1;
150 const u32 surface_height = static_cast<u32>(config.surface_height_minus1) + 1; 152 const u32 surface_height = static_cast<u32>(config.surface_height_minus1) + 1;
151 const u32 width = std::min(surface_width, static_cast<u32>(frame->width)); 153 const u32 width = std::min(surface_width, static_cast<u32>(frame_width));
152 const u32 height = std::min(surface_height, static_cast<u32>(frame->height)); 154 const u32 height = std::min(surface_height, static_cast<u32>(frame_height));
153 const u32 blk_kind = static_cast<u32>(config.block_linear_kind); 155 const u32 blk_kind = static_cast<u32>(config.block_linear_kind);
154 if (blk_kind != 0) { 156 if (blk_kind != 0) {
155 // swizzle pitch linear to block linear 157 // swizzle pitch linear to block linear
@@ -169,23 +171,23 @@ void Vic::WriteRGBFrame(const AVFrame* frame, const VicConfig& config) {
169 } 171 }
170} 172}
171 173
172void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) { 174void Vic::WriteYUVFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& config) {
173 LOG_TRACE(Service_NVDRV, "Writing YUV420 Frame"); 175 LOG_TRACE(Service_NVDRV, "Writing YUV420 Frame");
174 176
175 const std::size_t surface_width = config.surface_width_minus1 + 1; 177 const std::size_t surface_width = config.surface_width_minus1 + 1;
176 const std::size_t surface_height = config.surface_height_minus1 + 1; 178 const std::size_t surface_height = config.surface_height_minus1 + 1;
177 const std::size_t aligned_width = (surface_width + 0xff) & ~0xffUL; 179 const std::size_t aligned_width = (surface_width + 0xff) & ~0xffUL;
178 // Use the minimum of surface/frame dimensions to avoid buffer overflow. 180 // Use the minimum of surface/frame dimensions to avoid buffer overflow.
179 const auto frame_width = std::min(surface_width, static_cast<size_t>(frame->width)); 181 const auto frame_width = std::min(surface_width, static_cast<size_t>(frame->GetWidth()));
180 const auto frame_height = std::min(surface_height, static_cast<size_t>(frame->height)); 182 const auto frame_height = std::min(surface_height, static_cast<size_t>(frame->GetHeight()));
181 183
182 const auto stride = static_cast<size_t>(frame->linesize[0]); 184 const auto stride = static_cast<size_t>(frame->GetStride(0));
183 185
184 luma_buffer.resize_destructive(aligned_width * surface_height); 186 luma_buffer.resize_destructive(aligned_width * surface_height);
185 chroma_buffer.resize_destructive(aligned_width * surface_height / 2); 187 chroma_buffer.resize_destructive(aligned_width * surface_height / 2);
186 188
187 // Populate luma buffer 189 // Populate luma buffer
188 const u8* luma_src = frame->data[0]; 190 const u8* luma_src = frame->GetData(0);
189 for (std::size_t y = 0; y < frame_height; ++y) { 191 for (std::size_t y = 0; y < frame_height; ++y) {
190 const std::size_t src = y * stride; 192 const std::size_t src = y * stride;
191 const std::size_t dst = y * aligned_width; 193 const std::size_t dst = y * aligned_width;
@@ -196,16 +198,16 @@ void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) {
196 198
197 // Chroma 199 // Chroma
198 const std::size_t half_height = frame_height / 2; 200 const std::size_t half_height = frame_height / 2;
199 const auto half_stride = static_cast<size_t>(frame->linesize[1]); 201 const auto half_stride = static_cast<size_t>(frame->GetStride(1));
200 202
201 switch (frame->format) { 203 switch (frame->GetPixelFormat()) {
202 case AV_PIX_FMT_YUV420P: { 204 case AV_PIX_FMT_YUV420P: {
203 // Frame from FFmpeg software 205 // Frame from FFmpeg software
204 // Populate chroma buffer from both channels with interleaving. 206 // Populate chroma buffer from both channels with interleaving.
205 const std::size_t half_width = frame_width / 2; 207 const std::size_t half_width = frame_width / 2;
206 u8* chroma_buffer_data = chroma_buffer.data(); 208 u8* chroma_buffer_data = chroma_buffer.data();
207 const u8* chroma_b_src = frame->data[1]; 209 const u8* chroma_b_src = frame->GetData(1);
208 const u8* chroma_r_src = frame->data[2]; 210 const u8* chroma_r_src = frame->GetData(2);
209 for (std::size_t y = 0; y < half_height; ++y) { 211 for (std::size_t y = 0; y < half_height; ++y) {
210 const std::size_t src = y * half_stride; 212 const std::size_t src = y * half_stride;
211 const std::size_t dst = y * aligned_width; 213 const std::size_t dst = y * aligned_width;
@@ -219,7 +221,7 @@ void Vic::WriteYUVFrame(const AVFrame* frame, const VicConfig& config) {
219 case AV_PIX_FMT_NV12: { 221 case AV_PIX_FMT_NV12: {
220 // Frame from VA-API hardware 222 // Frame from VA-API hardware
221 // This is already interleaved so just copy 223 // This is already interleaved so just copy
222 const u8* chroma_src = frame->data[1]; 224 const u8* chroma_src = frame->GetData(1);
223 for (std::size_t y = 0; y < half_height; ++y) { 225 for (std::size_t y = 0; y < half_height; ++y) {
224 const std::size_t src = y * stride; 226 const std::size_t src = y * stride;
225 const std::size_t dst = y * aligned_width; 227 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:
39private: 39private:
40 void Execute(); 40 void Execute();
41 41
42 void WriteRGBFrame(const AVFrame* frame, const VicConfig& config); 42 void WriteRGBFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& config);
43 43
44 void WriteYUVFrame(const AVFrame* frame, const VicConfig& config); 44 void WriteYUVFrame(std::unique_ptr<FFmpeg::Frame> frame, const VicConfig& config);
45 45
46 Host1x& host1x; 46 Host1x& host1x;
47 std::shared_ptr<Tegra::Host1x::Nvdec> nvdec_processor; 47 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
266 return; 266 return;
267 } 267 }
268 if (False(query_base->flags & QueryFlagBits::IsFinalValueSynced)) [[unlikely]] { 268 if (False(query_base->flags & QueryFlagBits::IsFinalValueSynced)) [[unlikely]] {
269 UNREACHABLE(); 269 ASSERT(false);
270 return; 270 return;
271 } 271 }
272 query_base->value += streamer->GetAmmendValue(); 272 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
38 compatdb.ui 38 compatdb.ui
39 compatibility_list.cpp 39 compatibility_list.cpp
40 compatibility_list.h 40 compatibility_list.h
41 configuration/config.cpp
42 configuration/config.h
43 configuration/configuration_shared.cpp 41 configuration/configuration_shared.cpp
44 configuration/configuration_shared.h 42 configuration/configuration_shared.h
45 configuration/configure.ui 43 configuration/configure.ui
@@ -147,6 +145,8 @@ add_executable(yuzu
147 configuration/shared_translation.h 145 configuration/shared_translation.h
148 configuration/shared_widget.cpp 146 configuration/shared_widget.cpp
149 configuration/shared_widget.h 147 configuration/shared_widget.h
148 configuration/qt_config.cpp
149 configuration/qt_config.h
150 debugger/console.cpp 150 debugger/console.cpp
151 debugger/console.h 151 debugger/console.h
152 debugger/controller.cpp 152 debugger/controller.cpp
@@ -252,6 +252,7 @@ file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
252if (ENABLE_QT_TRANSLATION) 252if (ENABLE_QT_TRANSLATION)
253 set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend") 253 set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
254 option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF) 254 option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
255 option(WORKAROUND_BROKEN_LUPDATE "Run lupdate directly through CMake if Qt's convenience wrappers don't work" OFF)
255 256
256 # Update source TS file if enabled 257 # Update source TS file if enabled
257 if (GENERATE_QT_TRANSLATION) 258 if (GENERATE_QT_TRANSLATION)
@@ -259,19 +260,51 @@ if (ENABLE_QT_TRANSLATION)
259 # these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals 260 # these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals
260 # so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm 261 # so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm
261 set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations") 262 set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
262 qt_create_translation(QM_FILES 263 if (WORKAROUND_BROKEN_LUPDATE)
263 ${SRCS} 264 add_custom_command(OUTPUT ${YUZU_QT_LANGUAGES}/en.ts
264 ${UIS} 265 COMMAND lupdate
265 ${YUZU_QT_LANGUAGES}/en.ts 266 -source-language en_US
266 OPTIONS 267 -target-language en_US
267 -source-language en_US 268 ${SRCS}
268 -target-language en_US 269 ${UIS}
269 ) 270 -ts ${YUZU_QT_LANGUAGES}/en.ts
271 DEPENDS
272 ${SRCS}
273 ${UIS}
274 WORKING_DIRECTORY
275 ${CMAKE_CURRENT_SOURCE_DIR}
276 )
277 else()
278 qt_create_translation(QM_FILES
279 ${SRCS}
280 ${UIS}
281 ${YUZU_QT_LANGUAGES}/en.ts
282 OPTIONS
283 -source-language en_US
284 -target-language en_US
285 )
286 endif()
270 287
271 # Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts 288 # Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts
272 set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts) 289 set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts)
273 set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals") 290 set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals")
274 qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US) 291 if (WORKAROUND_BROKEN_LUPDATE)
292 add_custom_command(OUTPUT ${GENERATED_PLURALS_FILE}
293 COMMAND lupdate
294 -source-language en_US
295 -target-language en_US
296 ${SRCS}
297 ${UIS}
298 -ts ${GENERATED_PLURALS_FILE}
299 DEPENDS
300 ${SRCS}
301 ${UIS}
302 WORKING_DIRECTORY
303 ${CMAKE_CURRENT_SOURCE_DIR}
304 )
305 else()
306 qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
307 endif()
275 308
276 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE}) 309 add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE})
277 endif() 310 endif()
@@ -344,7 +377,7 @@ endif()
344 377
345create_target_directory_groups(yuzu) 378create_target_directory_groups(yuzu)
346 379
347target_link_libraries(yuzu PRIVATE common core input_common network video_core) 380target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core)
348target_link_libraries(yuzu PRIVATE Boost::headers glad Qt${QT_MAJOR_VERSION}::Widgets) 381target_link_libraries(yuzu PRIVATE Boost::headers glad Qt${QT_MAJOR_VERSION}::Widgets)
349target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 382target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
350 383
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 @@
1// SPDX-FileCopyrightText: 2014 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <array>
6#include <QKeySequence>
7#include <QSettings>
8#include "common/fs/fs.h"
9#include "common/fs/path_util.h"
10#include "common/settings.h"
11#include "common/settings_common.h"
12#include "common/settings_enums.h"
13#include "core/core.h"
14#include "core/hle/service/acc/profile_manager.h"
15#include "core/hle/service/hid/controllers/npad.h"
16#include "input_common/main.h"
17#include "network/network.h"
18#include "yuzu/configuration/config.h"
19
20namespace FS = Common::FS;
21
22Config::Config(const std::string& config_name, ConfigType config_type)
23 : type(config_type), global{config_type == ConfigType::GlobalConfig} {
24 Initialize(config_name);
25}
26
27Config::~Config() {
28 if (global) {
29 Save();
30 }
31}
32
33const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
34 Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F,
35 Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T,
36 Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right,
37 Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0,
38 Qt::Key_Q, Qt::Key_E,
39};
40
41const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = {
42 Qt::Key_7,
43 Qt::Key_8,
44};
45
46const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
47 {
48 Qt::Key_W,
49 Qt::Key_S,
50 Qt::Key_A,
51 Qt::Key_D,
52 },
53 {
54 Qt::Key_I,
55 Qt::Key_K,
56 Qt::Key_J,
57 Qt::Key_L,
58 },
59}};
60
61const std::array<int, 2> Config::default_stick_mod = {
62 Qt::Key_Shift,
63 0,
64};
65
66const std::array<int, 2> Config::default_ringcon_analogs{{
67 Qt::Key_A,
68 Qt::Key_D,
69}};
70
71const std::map<Settings::AntiAliasing, QString> Config::anti_aliasing_texts_map = {
72 {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))},
73 {Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))},
74 {Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))},
75};
76
77const std::map<Settings::ScalingFilter, QString> Config::scaling_filter_texts_map = {
78 {Settings::ScalingFilter::NearestNeighbor,
79 QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))},
80 {Settings::ScalingFilter::Bilinear,
81 QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))},
82 {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))},
83 {Settings::ScalingFilter::Gaussian,
84 QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))},
85 {Settings::ScalingFilter::ScaleForce,
86 QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))},
87 {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))},
88};
89
90const std::map<Settings::ConsoleMode, QString> Config::use_docked_mode_texts_map = {
91 {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))},
92 {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))},
93};
94
95const std::map<Settings::GpuAccuracy, QString> Config::gpu_accuracy_texts_map = {
96 {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))},
97 {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))},
98 {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))},
99};
100
101const std::map<Settings::RendererBackend, QString> Config::renderer_backend_texts_map = {
102 {Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))},
103 {Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))},
104 {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))},
105};
106
107const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_map = {
108 {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))},
109 {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))},
110 {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))},
111};
112
113// This shouldn't have anything except static initializers (no functions). So
114// QKeySequence(...).toString() is NOT ALLOWED HERE.
115// This must be in alphabetical order according to action name as it must have the same order as
116// UISetting::values.shortcuts, which is alphabetically ordered.
117// clang-format off
118const std::array<UISettings::Shortcut, 23> Config::default_hotkeys{{
119 {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}},
120 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
121 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
122 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut, false}},
123 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut, false}},
124 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut, false}},
125 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut, false}},
126 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut, false}},
127 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut, false}},
128 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut, false}},
129 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut, false}},
130 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut, false}},
131 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut, false}},
132 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral("R+Plus+Minus"), Qt::WindowShortcut, false}},
133 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral("L+Plus+Minus"), Qt::WindowShortcut, false}},
134 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
135 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
136 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
137 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}},
138 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}},
139 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
140 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral(""), QStringLiteral(""), Qt::ApplicationShortcut, false}},
141 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}},
142}};
143// clang-format on
144
145void Config::Initialize(const std::string& config_name) {
146 const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir);
147 const auto config_file = fmt::format("{}.ini", config_name);
148
149 switch (type) {
150 case ConfigType::GlobalConfig:
151 qt_config_loc = FS::PathToUTF8String(fs_config_loc / config_file);
152 void(FS::CreateParentDir(qt_config_loc));
153 qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
154 QSettings::IniFormat);
155 Reload();
156 break;
157 case ConfigType::PerGameConfig:
158 qt_config_loc =
159 FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file));
160 void(FS::CreateParentDir(qt_config_loc));
161 qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
162 QSettings::IniFormat);
163 Reload();
164 break;
165 case ConfigType::InputProfile:
166 qt_config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file);
167 void(FS::CreateParentDir(qt_config_loc));
168 qt_config = std::make_unique<QSettings>(QString::fromStdString(qt_config_loc),
169 QSettings::IniFormat);
170 break;
171 }
172}
173
174bool Config::IsCustomConfig() {
175 return type == ConfigType::PerGameConfig;
176}
177
178void Config::ReadPlayerValue(std::size_t player_index) {
179 const QString player_prefix = [this, player_index] {
180 if (type == ConfigType::InputProfile) {
181 return QString{};
182 } else {
183 return QStringLiteral("player_%1_").arg(player_index);
184 }
185 }();
186
187 auto& player = Settings::values.players.GetValue()[player_index];
188 if (IsCustomConfig()) {
189 const auto profile_name =
190 qt_config->value(QStringLiteral("%1profile_name").arg(player_prefix), QString{})
191 .toString()
192 .toStdString();
193 if (profile_name.empty()) {
194 // Use the global input config
195 player = Settings::values.players.GetValue(true)[player_index];
196 return;
197 }
198 player.profile_name = profile_name;
199 }
200
201 if (player_prefix.isEmpty() && Settings::IsConfiguringGlobal()) {
202 const auto controller = static_cast<Settings::ControllerType>(
203 qt_config
204 ->value(QStringLiteral("%1type").arg(player_prefix),
205 static_cast<u8>(Settings::ControllerType::ProController))
206 .toUInt());
207
208 if (controller == Settings::ControllerType::LeftJoycon ||
209 controller == Settings::ControllerType::RightJoycon) {
210 player.controller_type = controller;
211 }
212 } else {
213 player.connected =
214 ReadSetting(QStringLiteral("%1connected").arg(player_prefix), player_index == 0)
215 .toBool();
216
217 player.controller_type = static_cast<Settings::ControllerType>(
218 qt_config
219 ->value(QStringLiteral("%1type").arg(player_prefix),
220 static_cast<u8>(Settings::ControllerType::ProController))
221 .toUInt());
222
223 player.vibration_enabled =
224 qt_config->value(QStringLiteral("%1vibration_enabled").arg(player_prefix), true)
225 .toBool();
226
227 player.vibration_strength =
228 qt_config->value(QStringLiteral("%1vibration_strength").arg(player_prefix), 100)
229 .toInt();
230
231 player.body_color_left = qt_config
232 ->value(QStringLiteral("%1body_color_left").arg(player_prefix),
233 Settings::JOYCON_BODY_NEON_BLUE)
234 .toUInt();
235 player.body_color_right =
236 qt_config
237 ->value(QStringLiteral("%1body_color_right").arg(player_prefix),
238 Settings::JOYCON_BODY_NEON_RED)
239 .toUInt();
240 player.button_color_left =
241 qt_config
242 ->value(QStringLiteral("%1button_color_left").arg(player_prefix),
243 Settings::JOYCON_BUTTONS_NEON_BLUE)
244 .toUInt();
245 player.button_color_right =
246 qt_config
247 ->value(QStringLiteral("%1button_color_right").arg(player_prefix),
248 Settings::JOYCON_BUTTONS_NEON_RED)
249 .toUInt();
250 }
251
252 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
253 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
254 auto& player_buttons = player.buttons[i];
255
256 player_buttons = qt_config
257 ->value(QStringLiteral("%1").arg(player_prefix) +
258 QString::fromUtf8(Settings::NativeButton::mapping[i]),
259 QString::fromStdString(default_param))
260 .toString()
261 .toStdString();
262 if (player_buttons.empty()) {
263 player_buttons = default_param;
264 }
265 }
266
267 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
268 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
269 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
270 default_analogs[i][3], default_stick_mod[i], 0.5f);
271 auto& player_analogs = player.analogs[i];
272
273 player_analogs = qt_config
274 ->value(QStringLiteral("%1").arg(player_prefix) +
275 QString::fromUtf8(Settings::NativeAnalog::mapping[i]),
276 QString::fromStdString(default_param))
277 .toString()
278 .toStdString();
279 if (player_analogs.empty()) {
280 player_analogs = default_param;
281 }
282 }
283
284 for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
285 const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
286 auto& player_motions = player.motions[i];
287
288 player_motions = qt_config
289 ->value(QStringLiteral("%1").arg(player_prefix) +
290 QString::fromUtf8(Settings::NativeMotion::mapping[i]),
291 QString::fromStdString(default_param))
292 .toString()
293 .toStdString();
294 if (player_motions.empty()) {
295 player_motions = default_param;
296 }
297 }
298}
299
300void Config::ReadDebugValues() {
301 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
302 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
303 auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i];
304
305 debug_pad_buttons = qt_config
306 ->value(QStringLiteral("debug_pad_") +
307 QString::fromUtf8(Settings::NativeButton::mapping[i]),
308 QString::fromStdString(default_param))
309 .toString()
310 .toStdString();
311 if (debug_pad_buttons.empty()) {
312 debug_pad_buttons = default_param;
313 }
314 }
315
316 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
317 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
318 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
319 default_analogs[i][3], default_stick_mod[i], 0.5f);
320 auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
321
322 debug_pad_analogs = qt_config
323 ->value(QStringLiteral("debug_pad_") +
324 QString::fromUtf8(Settings::NativeAnalog::mapping[i]),
325 QString::fromStdString(default_param))
326 .toString()
327 .toStdString();
328 if (debug_pad_analogs.empty()) {
329 debug_pad_analogs = default_param;
330 }
331 }
332}
333
334void Config::ReadTouchscreenValues() {
335 Settings::values.touchscreen.enabled =
336 ReadSetting(QStringLiteral("touchscreen_enabled"), true).toBool();
337
338 Settings::values.touchscreen.rotation_angle =
339 ReadSetting(QStringLiteral("touchscreen_angle"), 0).toUInt();
340 Settings::values.touchscreen.diameter_x =
341 ReadSetting(QStringLiteral("touchscreen_diameter_x"), 15).toUInt();
342 Settings::values.touchscreen.diameter_y =
343 ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt();
344}
345
346void Config::ReadHidbusValues() {
347 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
348 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
349 auto& ringcon_analogs = Settings::values.ringcon_analogs;
350
351 ringcon_analogs =
352 qt_config->value(QStringLiteral("ring_controller"), QString::fromStdString(default_param))
353 .toString()
354 .toStdString();
355 if (ringcon_analogs.empty()) {
356 ringcon_analogs = default_param;
357 }
358}
359
360void Config::ReadAudioValues() {
361 qt_config->beginGroup(QStringLiteral("Audio"));
362
363 ReadCategory(Settings::Category::Audio);
364 ReadCategory(Settings::Category::UiAudio);
365
366 qt_config->endGroup();
367}
368
369void Config::ReadControlValues() {
370 qt_config->beginGroup(QStringLiteral("Controls"));
371
372 ReadCategory(Settings::Category::Controls);
373
374 Settings::values.players.SetGlobal(!IsCustomConfig());
375 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
376 ReadPlayerValue(p);
377 }
378
379 // Disable docked mode if handheld is selected
380 const auto controller_type = Settings::values.players.GetValue()[0].controller_type;
381 if (controller_type == Settings::ControllerType::Handheld) {
382 Settings::values.use_docked_mode.SetGlobal(!IsCustomConfig());
383 Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld);
384 }
385
386 if (IsCustomConfig()) {
387 qt_config->endGroup();
388 return;
389 }
390 ReadDebugValues();
391 ReadTouchscreenValues();
392 ReadMotionTouchValues();
393 ReadHidbusValues();
394
395 qt_config->endGroup();
396}
397
398void Config::ReadMotionTouchValues() {
399 int num_touch_from_button_maps =
400 qt_config->beginReadArray(QStringLiteral("touch_from_button_maps"));
401
402 if (num_touch_from_button_maps > 0) {
403 const auto append_touch_from_button_map = [this] {
404 Settings::TouchFromButtonMap map;
405 map.name = ReadSetting(QStringLiteral("name"), QStringLiteral("default"))
406 .toString()
407 .toStdString();
408 const int num_touch_maps = qt_config->beginReadArray(QStringLiteral("entries"));
409 map.buttons.reserve(num_touch_maps);
410 for (int i = 0; i < num_touch_maps; i++) {
411 qt_config->setArrayIndex(i);
412 std::string touch_mapping =
413 ReadSetting(QStringLiteral("bind")).toString().toStdString();
414 map.buttons.emplace_back(std::move(touch_mapping));
415 }
416 qt_config->endArray(); // entries
417 Settings::values.touch_from_button_maps.emplace_back(std::move(map));
418 };
419
420 for (int i = 0; i < num_touch_from_button_maps; ++i) {
421 qt_config->setArrayIndex(i);
422 append_touch_from_button_map();
423 }
424 } else {
425 Settings::values.touch_from_button_maps.emplace_back(
426 Settings::TouchFromButtonMap{"default", {}});
427 num_touch_from_button_maps = 1;
428 }
429 qt_config->endArray();
430
431 Settings::values.touch_from_button_map_index = std::clamp(
432 Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
433}
434
435void Config::ReadCoreValues() {
436 qt_config->beginGroup(QStringLiteral("Core"));
437
438 ReadCategory(Settings::Category::Core);
439
440 qt_config->endGroup();
441}
442
443void Config::ReadDataStorageValues() {
444 qt_config->beginGroup(QStringLiteral("Data Storage"));
445
446 FS::SetYuzuPath(
447 FS::YuzuPath::NANDDir,
448 qt_config
449 ->value(QStringLiteral("nand_directory"),
450 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)))
451 .toString()
452 .toStdString());
453 FS::SetYuzuPath(
454 FS::YuzuPath::SDMCDir,
455 qt_config
456 ->value(QStringLiteral("sdmc_directory"),
457 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)))
458 .toString()
459 .toStdString());
460 FS::SetYuzuPath(
461 FS::YuzuPath::LoadDir,
462 qt_config
463 ->value(QStringLiteral("load_directory"),
464 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)))
465 .toString()
466 .toStdString());
467 FS::SetYuzuPath(
468 FS::YuzuPath::DumpDir,
469 qt_config
470 ->value(QStringLiteral("dump_directory"),
471 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)))
472 .toString()
473 .toStdString());
474 FS::SetYuzuPath(FS::YuzuPath::TASDir,
475 qt_config
476 ->value(QStringLiteral("tas_directory"),
477 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir)))
478 .toString()
479 .toStdString());
480
481 ReadCategory(Settings::Category::DataStorage);
482
483 qt_config->endGroup();
484}
485
486void Config::ReadDebuggingValues() {
487 qt_config->beginGroup(QStringLiteral("Debugging"));
488
489 // Intentionally not using the QT default setting as this is intended to be changed in the ini
490 Settings::values.record_frame_times =
491 qt_config->value(QStringLiteral("record_frame_times"), false).toBool();
492
493 ReadCategory(Settings::Category::Debugging);
494 ReadCategory(Settings::Category::DebuggingGraphics);
495
496 qt_config->endGroup();
497}
498
499void Config::ReadServiceValues() {
500 qt_config->beginGroup(QStringLiteral("Services"));
501
502 ReadCategory(Settings::Category::Services);
503
504 qt_config->endGroup();
505}
506
507void Config::ReadDisabledAddOnValues() {
508 const auto size = qt_config->beginReadArray(QStringLiteral("DisabledAddOns"));
509
510 for (int i = 0; i < size; ++i) {
511 qt_config->setArrayIndex(i);
512 const auto title_id = ReadSetting(QStringLiteral("title_id"), 0).toULongLong();
513 std::vector<std::string> out;
514 const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled"));
515 for (int j = 0; j < d_size; ++j) {
516 qt_config->setArrayIndex(j);
517 out.push_back(ReadSetting(QStringLiteral("d"), QString{}).toString().toStdString());
518 }
519 qt_config->endArray();
520 Settings::values.disabled_addons.insert_or_assign(title_id, out);
521 }
522
523 qt_config->endArray();
524}
525
526void Config::ReadMiscellaneousValues() {
527 qt_config->beginGroup(QStringLiteral("Miscellaneous"));
528
529 ReadCategory(Settings::Category::Miscellaneous);
530
531 qt_config->endGroup();
532}
533
534void Config::ReadPathValues() {
535 qt_config->beginGroup(QStringLiteral("Paths"));
536
537 UISettings::values.roms_path = ReadSetting(QStringLiteral("romsPath")).toString();
538 UISettings::values.symbols_path = ReadSetting(QStringLiteral("symbolsPath")).toString();
539 UISettings::values.game_dir_deprecated =
540 ReadSetting(QStringLiteral("gameListRootDir"), QStringLiteral(".")).toString();
541 UISettings::values.game_dir_deprecated_deepscan =
542 ReadSetting(QStringLiteral("gameListDeepScan"), false).toBool();
543 const int gamedirs_size = qt_config->beginReadArray(QStringLiteral("gamedirs"));
544 for (int i = 0; i < gamedirs_size; ++i) {
545 qt_config->setArrayIndex(i);
546 UISettings::GameDir game_dir;
547 game_dir.path = ReadSetting(QStringLiteral("path")).toString();
548 game_dir.deep_scan = ReadSetting(QStringLiteral("deep_scan"), false).toBool();
549 game_dir.expanded = ReadSetting(QStringLiteral("expanded"), true).toBool();
550 UISettings::values.game_dirs.append(game_dir);
551 }
552 qt_config->endArray();
553 // create NAND and SD card directories if empty, these are not removable through the UI,
554 // also carries over old game list settings if present
555 if (UISettings::values.game_dirs.isEmpty()) {
556 UISettings::GameDir game_dir;
557 game_dir.path = QStringLiteral("SDMC");
558 game_dir.expanded = true;
559 UISettings::values.game_dirs.append(game_dir);
560 game_dir.path = QStringLiteral("UserNAND");
561 UISettings::values.game_dirs.append(game_dir);
562 game_dir.path = QStringLiteral("SysNAND");
563 UISettings::values.game_dirs.append(game_dir);
564 if (UISettings::values.game_dir_deprecated != QStringLiteral(".")) {
565 game_dir.path = UISettings::values.game_dir_deprecated;
566 game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan;
567 UISettings::values.game_dirs.append(game_dir);
568 }
569 }
570 UISettings::values.recent_files = ReadSetting(QStringLiteral("recentFiles")).toStringList();
571 UISettings::values.language = ReadSetting(QStringLiteral("language"), QString{}).toString();
572
573 qt_config->endGroup();
574}
575
576void Config::ReadCpuValues() {
577 qt_config->beginGroup(QStringLiteral("Cpu"));
578
579 ReadCategory(Settings::Category::Cpu);
580 ReadCategory(Settings::Category::CpuDebug);
581 ReadCategory(Settings::Category::CpuUnsafe);
582
583 qt_config->endGroup();
584}
585
586void Config::ReadRendererValues() {
587 qt_config->beginGroup(QStringLiteral("Renderer"));
588
589 ReadCategory(Settings::Category::Renderer);
590 ReadCategory(Settings::Category::RendererAdvanced);
591 ReadCategory(Settings::Category::RendererDebug);
592
593 qt_config->endGroup();
594}
595
596void Config::ReadScreenshotValues() {
597 qt_config->beginGroup(QStringLiteral("Screenshots"));
598
599 ReadCategory(Settings::Category::Screenshots);
600 FS::SetYuzuPath(
601 FS::YuzuPath::ScreenshotsDir,
602 qt_config
603 ->value(QStringLiteral("screenshot_path"),
604 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)))
605 .toString()
606 .toStdString());
607
608 qt_config->endGroup();
609}
610
611void Config::ReadShortcutValues() {
612 qt_config->beginGroup(QStringLiteral("Shortcuts"));
613
614 for (const auto& [name, group, shortcut] : default_hotkeys) {
615 qt_config->beginGroup(group);
616 qt_config->beginGroup(name);
617 // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1
618 // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open
619 // a file dialog in windowed mode
620 UISettings::values.shortcuts.push_back(
621 {name,
622 group,
623 {ReadSetting(QStringLiteral("KeySeq"), shortcut.keyseq).toString(),
624 ReadSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq)
625 .toString(),
626 shortcut.context, ReadSetting(QStringLiteral("Repeat"), shortcut.repeat).toBool()}});
627 qt_config->endGroup();
628 qt_config->endGroup();
629 }
630
631 qt_config->endGroup();
632}
633
634void Config::ReadSystemValues() {
635 qt_config->beginGroup(QStringLiteral("System"));
636
637 ReadCategory(Settings::Category::System);
638 ReadCategory(Settings::Category::SystemAudio);
639
640 qt_config->endGroup();
641}
642
643void Config::ReadUIValues() {
644 qt_config->beginGroup(QStringLiteral("UI"));
645
646 UISettings::values.theme =
647 ReadSetting(
648 QStringLiteral("theme"),
649 QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second))
650 .toString();
651
652 ReadUIGamelistValues();
653 ReadUILayoutValues();
654 ReadPathValues();
655 ReadScreenshotValues();
656 ReadShortcutValues();
657 ReadMultiplayerValues();
658
659 ReadCategory(Settings::Category::Ui);
660 ReadCategory(Settings::Category::UiGeneral);
661
662 qt_config->endGroup();
663}
664
665void Config::ReadUIGamelistValues() {
666 qt_config->beginGroup(QStringLiteral("UIGameList"));
667
668 ReadCategory(Settings::Category::UiGameList);
669
670 const int favorites_size = qt_config->beginReadArray(QStringLiteral("favorites"));
671 for (int i = 0; i < favorites_size; i++) {
672 qt_config->setArrayIndex(i);
673 UISettings::values.favorited_ids.append(
674 ReadSetting(QStringLiteral("program_id")).toULongLong());
675 }
676 qt_config->endArray();
677
678 qt_config->endGroup();
679}
680
681void Config::ReadUILayoutValues() {
682 qt_config->beginGroup(QStringLiteral("UILayout"));
683
684 UISettings::values.geometry = ReadSetting(QStringLiteral("geometry")).toByteArray();
685 UISettings::values.state = ReadSetting(QStringLiteral("state")).toByteArray();
686 UISettings::values.renderwindow_geometry =
687 ReadSetting(QStringLiteral("geometryRenderWindow")).toByteArray();
688 UISettings::values.gamelist_header_state =
689 ReadSetting(QStringLiteral("gameListHeaderState")).toByteArray();
690 UISettings::values.microprofile_geometry =
691 ReadSetting(QStringLiteral("microProfileDialogGeometry")).toByteArray();
692
693 ReadCategory(Settings::Category::UiLayout);
694
695 qt_config->endGroup();
696}
697
698void Config::ReadWebServiceValues() {
699 qt_config->beginGroup(QStringLiteral("WebService"));
700
701 ReadCategory(Settings::Category::WebService);
702
703 qt_config->endGroup();
704}
705
706void Config::ReadMultiplayerValues() {
707 qt_config->beginGroup(QStringLiteral("Multiplayer"));
708
709 ReadCategory(Settings::Category::Multiplayer);
710
711 // Read ban list back
712 int size = qt_config->beginReadArray(QStringLiteral("username_ban_list"));
713 UISettings::values.multiplayer_ban_list.first.resize(size);
714 for (int i = 0; i < size; ++i) {
715 qt_config->setArrayIndex(i);
716 UISettings::values.multiplayer_ban_list.first[i] =
717 ReadSetting(QStringLiteral("username")).toString().toStdString();
718 }
719 qt_config->endArray();
720 size = qt_config->beginReadArray(QStringLiteral("ip_ban_list"));
721 UISettings::values.multiplayer_ban_list.second.resize(size);
722 for (int i = 0; i < size; ++i) {
723 qt_config->setArrayIndex(i);
724 UISettings::values.multiplayer_ban_list.second[i] =
725 ReadSetting(QStringLiteral("ip")).toString().toStdString();
726 }
727 qt_config->endArray();
728
729 qt_config->endGroup();
730}
731
732void Config::ReadNetworkValues() {
733 qt_config->beginGroup(QString::fromStdString("Services"));
734
735 ReadCategory(Settings::Category::Network);
736
737 qt_config->endGroup();
738}
739
740void Config::ReadValues() {
741 if (global) {
742 ReadDataStorageValues();
743 ReadDebuggingValues();
744 ReadDisabledAddOnValues();
745 ReadNetworkValues();
746 ReadServiceValues();
747 ReadUIValues();
748 ReadWebServiceValues();
749 ReadMiscellaneousValues();
750 }
751 ReadControlValues();
752 ReadCoreValues();
753 ReadCpuValues();
754 ReadRendererValues();
755 ReadAudioValues();
756 ReadSystemValues();
757}
758
759void Config::SavePlayerValue(std::size_t player_index) {
760 const QString player_prefix = [this, player_index] {
761 if (type == ConfigType::InputProfile) {
762 return QString{};
763 } else {
764 return QStringLiteral("player_%1_").arg(player_index);
765 }
766 }();
767
768 const auto& player = Settings::values.players.GetValue()[player_index];
769 if (IsCustomConfig()) {
770 if (player.profile_name.empty()) {
771 // No custom profile selected
772 return;
773 }
774 WriteSetting(QStringLiteral("%1profile_name").arg(player_prefix),
775 QString::fromStdString(player.profile_name), QString{});
776 }
777
778 WriteSetting(QStringLiteral("%1type").arg(player_prefix),
779 static_cast<u8>(player.controller_type),
780 static_cast<u8>(Settings::ControllerType::ProController));
781
782 if (!player_prefix.isEmpty() || !Settings::IsConfiguringGlobal()) {
783 WriteSetting(QStringLiteral("%1connected").arg(player_prefix), player.connected,
784 player_index == 0);
785 WriteSetting(QStringLiteral("%1vibration_enabled").arg(player_prefix),
786 player.vibration_enabled, true);
787 WriteSetting(QStringLiteral("%1vibration_strength").arg(player_prefix),
788 player.vibration_strength, 100);
789 WriteSetting(QStringLiteral("%1body_color_left").arg(player_prefix), player.body_color_left,
790 Settings::JOYCON_BODY_NEON_BLUE);
791 WriteSetting(QStringLiteral("%1body_color_right").arg(player_prefix),
792 player.body_color_right, Settings::JOYCON_BODY_NEON_RED);
793 WriteSetting(QStringLiteral("%1button_color_left").arg(player_prefix),
794 player.button_color_left, Settings::JOYCON_BUTTONS_NEON_BLUE);
795 WriteSetting(QStringLiteral("%1button_color_right").arg(player_prefix),
796 player.button_color_right, Settings::JOYCON_BUTTONS_NEON_RED);
797 }
798
799 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
800 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
801 WriteSetting(QStringLiteral("%1").arg(player_prefix) +
802 QString::fromStdString(Settings::NativeButton::mapping[i]),
803 QString::fromStdString(player.buttons[i]),
804 QString::fromStdString(default_param));
805 }
806 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
807 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
808 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
809 default_analogs[i][3], default_stick_mod[i], 0.5f);
810 WriteSetting(QStringLiteral("%1").arg(player_prefix) +
811 QString::fromStdString(Settings::NativeAnalog::mapping[i]),
812 QString::fromStdString(player.analogs[i]),
813 QString::fromStdString(default_param));
814 }
815 for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
816 const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
817 WriteSetting(QStringLiteral("%1").arg(player_prefix) +
818 QString::fromStdString(Settings::NativeMotion::mapping[i]),
819 QString::fromStdString(player.motions[i]),
820 QString::fromStdString(default_param));
821 }
822}
823
824void Config::SaveDebugValues() {
825 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
826 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
827 WriteSetting(QStringLiteral("debug_pad_") +
828 QString::fromStdString(Settings::NativeButton::mapping[i]),
829 QString::fromStdString(Settings::values.debug_pad_buttons[i]),
830 QString::fromStdString(default_param));
831 }
832 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
833 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
834 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
835 default_analogs[i][3], default_stick_mod[i], 0.5f);
836 WriteSetting(QStringLiteral("debug_pad_") +
837 QString::fromStdString(Settings::NativeAnalog::mapping[i]),
838 QString::fromStdString(Settings::values.debug_pad_analogs[i]),
839 QString::fromStdString(default_param));
840 }
841}
842
843void Config::SaveTouchscreenValues() {
844 const auto& touchscreen = Settings::values.touchscreen;
845
846 WriteSetting(QStringLiteral("touchscreen_enabled"), touchscreen.enabled, true);
847
848 WriteSetting(QStringLiteral("touchscreen_angle"), touchscreen.rotation_angle, 0);
849 WriteSetting(QStringLiteral("touchscreen_diameter_x"), touchscreen.diameter_x, 15);
850 WriteSetting(QStringLiteral("touchscreen_diameter_y"), touchscreen.diameter_y, 15);
851}
852
853void Config::SaveMotionTouchValues() {
854 qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps"));
855 for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) {
856 qt_config->setArrayIndex(static_cast<int>(p));
857 WriteSetting(QStringLiteral("name"),
858 QString::fromStdString(Settings::values.touch_from_button_maps[p].name),
859 QStringLiteral("default"));
860 qt_config->beginWriteArray(QStringLiteral("entries"));
861 for (std::size_t q = 0; q < Settings::values.touch_from_button_maps[p].buttons.size();
862 ++q) {
863 qt_config->setArrayIndex(static_cast<int>(q));
864 WriteSetting(
865 QStringLiteral("bind"),
866 QString::fromStdString(Settings::values.touch_from_button_maps[p].buttons[q]));
867 }
868 qt_config->endArray();
869 }
870 qt_config->endArray();
871}
872
873void Config::SaveHidbusValues() {
874 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
875 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
876 WriteSetting(QStringLiteral("ring_controller"),
877 QString::fromStdString(Settings::values.ringcon_analogs),
878 QString::fromStdString(default_param));
879}
880
881void Config::SaveValues() {
882 if (global) {
883 SaveDataStorageValues();
884 SaveDebuggingValues();
885 SaveDisabledAddOnValues();
886 SaveNetworkValues();
887 SaveUIValues();
888 SaveWebServiceValues();
889 SaveMiscellaneousValues();
890 }
891 SaveControlValues();
892 SaveCoreValues();
893 SaveCpuValues();
894 SaveRendererValues();
895 SaveAudioValues();
896 SaveSystemValues();
897
898 qt_config->sync();
899}
900
901void Config::SaveAudioValues() {
902 qt_config->beginGroup(QStringLiteral("Audio"));
903
904 WriteCategory(Settings::Category::Audio);
905 WriteCategory(Settings::Category::UiAudio);
906
907 qt_config->endGroup();
908}
909
910void Config::SaveControlValues() {
911 qt_config->beginGroup(QStringLiteral("Controls"));
912
913 WriteCategory(Settings::Category::Controls);
914
915 Settings::values.players.SetGlobal(!IsCustomConfig());
916 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
917 SavePlayerValue(p);
918 }
919 if (IsCustomConfig()) {
920 qt_config->endGroup();
921 return;
922 }
923 SaveDebugValues();
924 SaveTouchscreenValues();
925 SaveMotionTouchValues();
926 SaveHidbusValues();
927
928 qt_config->endGroup();
929}
930
931void Config::SaveCoreValues() {
932 qt_config->beginGroup(QStringLiteral("Core"));
933
934 WriteCategory(Settings::Category::Core);
935
936 qt_config->endGroup();
937}
938
939void Config::SaveDataStorageValues() {
940 qt_config->beginGroup(QStringLiteral("Data Storage"));
941
942 WriteSetting(QStringLiteral("nand_directory"),
943 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)),
944 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
945 WriteSetting(QStringLiteral("sdmc_directory"),
946 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)),
947 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
948 WriteSetting(QStringLiteral("load_directory"),
949 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)),
950 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
951 WriteSetting(QStringLiteral("dump_directory"),
952 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)),
953 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
954 WriteSetting(QStringLiteral("tas_directory"),
955 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir)),
956 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::TASDir)));
957
958 WriteCategory(Settings::Category::DataStorage);
959
960 qt_config->endGroup();
961}
962
963void Config::SaveDebuggingValues() {
964 qt_config->beginGroup(QStringLiteral("Debugging"));
965
966 // Intentionally not using the QT default setting as this is intended to be changed in the ini
967 qt_config->setValue(QStringLiteral("record_frame_times"), Settings::values.record_frame_times);
968
969 WriteCategory(Settings::Category::Debugging);
970 WriteCategory(Settings::Category::DebuggingGraphics);
971
972 qt_config->endGroup();
973}
974
975void Config::SaveNetworkValues() {
976 qt_config->beginGroup(QStringLiteral("Services"));
977
978 WriteCategory(Settings::Category::Network);
979
980 qt_config->endGroup();
981}
982
983void Config::SaveDisabledAddOnValues() {
984 qt_config->beginWriteArray(QStringLiteral("DisabledAddOns"));
985
986 int i = 0;
987 for (const auto& elem : Settings::values.disabled_addons) {
988 qt_config->setArrayIndex(i);
989 WriteSetting(QStringLiteral("title_id"), QVariant::fromValue<u64>(elem.first), 0);
990 qt_config->beginWriteArray(QStringLiteral("disabled"));
991 for (std::size_t j = 0; j < elem.second.size(); ++j) {
992 qt_config->setArrayIndex(static_cast<int>(j));
993 WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), QString{});
994 }
995 qt_config->endArray();
996 ++i;
997 }
998
999 qt_config->endArray();
1000}
1001
1002void Config::SaveMiscellaneousValues() {
1003 qt_config->beginGroup(QStringLiteral("Miscellaneous"));
1004
1005 WriteCategory(Settings::Category::Miscellaneous);
1006
1007 qt_config->endGroup();
1008}
1009
1010void Config::SavePathValues() {
1011 qt_config->beginGroup(QStringLiteral("Paths"));
1012
1013 WriteSetting(QStringLiteral("romsPath"), UISettings::values.roms_path);
1014 WriteSetting(QStringLiteral("symbolsPath"), UISettings::values.symbols_path);
1015 qt_config->beginWriteArray(QStringLiteral("gamedirs"));
1016 for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) {
1017 qt_config->setArrayIndex(i);
1018 const auto& game_dir = UISettings::values.game_dirs[i];
1019 WriteSetting(QStringLiteral("path"), game_dir.path);
1020 WriteSetting(QStringLiteral("deep_scan"), game_dir.deep_scan, false);
1021 WriteSetting(QStringLiteral("expanded"), game_dir.expanded, true);
1022 }
1023 qt_config->endArray();
1024 WriteSetting(QStringLiteral("recentFiles"), UISettings::values.recent_files);
1025 WriteSetting(QStringLiteral("language"), UISettings::values.language, QString{});
1026
1027 qt_config->endGroup();
1028}
1029
1030void Config::SaveCpuValues() {
1031 qt_config->beginGroup(QStringLiteral("Cpu"));
1032
1033 WriteCategory(Settings::Category::Cpu);
1034 WriteCategory(Settings::Category::CpuDebug);
1035 WriteCategory(Settings::Category::CpuUnsafe);
1036
1037 qt_config->endGroup();
1038}
1039
1040void Config::SaveRendererValues() {
1041 qt_config->beginGroup(QStringLiteral("Renderer"));
1042
1043 WriteCategory(Settings::Category::Renderer);
1044 WriteCategory(Settings::Category::RendererAdvanced);
1045 WriteCategory(Settings::Category::RendererDebug);
1046
1047 qt_config->endGroup();
1048}
1049
1050void Config::SaveScreenshotValues() {
1051 qt_config->beginGroup(QStringLiteral("Screenshots"));
1052
1053 WriteSetting(QStringLiteral("screenshot_path"),
1054 QString::fromStdString(FS::GetYuzuPathString(FS::YuzuPath::ScreenshotsDir)));
1055 WriteCategory(Settings::Category::Screenshots);
1056
1057 qt_config->endGroup();
1058}
1059
1060void Config::SaveShortcutValues() {
1061 qt_config->beginGroup(QStringLiteral("Shortcuts"));
1062
1063 // Lengths of UISettings::values.shortcuts & default_hotkeys are same.
1064 // However, their ordering must also be the same.
1065 for (std::size_t i = 0; i < default_hotkeys.size(); i++) {
1066 const auto& [name, group, shortcut] = UISettings::values.shortcuts[i];
1067 const auto& default_hotkey = default_hotkeys[i].shortcut;
1068
1069 qt_config->beginGroup(group);
1070 qt_config->beginGroup(name);
1071 WriteSetting(QStringLiteral("KeySeq"), shortcut.keyseq, default_hotkey.keyseq);
1072 WriteSetting(QStringLiteral("Controller_KeySeq"), shortcut.controller_keyseq,
1073 default_hotkey.controller_keyseq);
1074 WriteSetting(QStringLiteral("Context"), shortcut.context, default_hotkey.context);
1075 WriteSetting(QStringLiteral("Repeat"), shortcut.repeat, default_hotkey.repeat);
1076 qt_config->endGroup();
1077 qt_config->endGroup();
1078 }
1079
1080 qt_config->endGroup();
1081}
1082
1083void Config::SaveSystemValues() {
1084 qt_config->beginGroup(QStringLiteral("System"));
1085
1086 WriteCategory(Settings::Category::System);
1087 WriteCategory(Settings::Category::SystemAudio);
1088
1089 qt_config->endGroup();
1090}
1091
1092void Config::SaveUIValues() {
1093 qt_config->beginGroup(QStringLiteral("UI"));
1094
1095 WriteCategory(Settings::Category::Ui);
1096 WriteCategory(Settings::Category::UiGeneral);
1097
1098 WriteSetting(QStringLiteral("theme"), UISettings::values.theme,
1099 QString::fromUtf8(UISettings::themes[static_cast<size_t>(default_theme)].second));
1100
1101 SaveUIGamelistValues();
1102 SaveUILayoutValues();
1103 SavePathValues();
1104 SaveScreenshotValues();
1105 SaveShortcutValues();
1106 SaveMultiplayerValues();
1107
1108 qt_config->endGroup();
1109}
1110
1111void Config::SaveUIGamelistValues() {
1112 qt_config->beginGroup(QStringLiteral("UIGameList"));
1113
1114 WriteCategory(Settings::Category::UiGameList);
1115
1116 qt_config->beginWriteArray(QStringLiteral("favorites"));
1117 for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
1118 qt_config->setArrayIndex(i);
1119 WriteSetting(QStringLiteral("program_id"),
1120 QVariant::fromValue(UISettings::values.favorited_ids[i]));
1121 }
1122 qt_config->endArray();
1123
1124 qt_config->endGroup();
1125}
1126
1127void Config::SaveUILayoutValues() {
1128 qt_config->beginGroup(QStringLiteral("UILayout"));
1129
1130 WriteSetting(QStringLiteral("geometry"), UISettings::values.geometry);
1131 WriteSetting(QStringLiteral("state"), UISettings::values.state);
1132 WriteSetting(QStringLiteral("geometryRenderWindow"), UISettings::values.renderwindow_geometry);
1133 WriteSetting(QStringLiteral("gameListHeaderState"), UISettings::values.gamelist_header_state);
1134 WriteSetting(QStringLiteral("microProfileDialogGeometry"),
1135 UISettings::values.microprofile_geometry);
1136
1137 WriteCategory(Settings::Category::UiLayout);
1138
1139 qt_config->endGroup();
1140}
1141
1142void Config::SaveWebServiceValues() {
1143 qt_config->beginGroup(QStringLiteral("WebService"));
1144
1145 WriteCategory(Settings::Category::WebService);
1146
1147 qt_config->endGroup();
1148}
1149
1150void Config::SaveMultiplayerValues() {
1151 qt_config->beginGroup(QStringLiteral("Multiplayer"));
1152
1153 WriteCategory(Settings::Category::Multiplayer);
1154
1155 // Write ban list
1156 qt_config->beginWriteArray(QStringLiteral("username_ban_list"));
1157 for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) {
1158 qt_config->setArrayIndex(static_cast<int>(i));
1159 WriteSetting(QStringLiteral("username"),
1160 QString::fromStdString(UISettings::values.multiplayer_ban_list.first[i]));
1161 }
1162 qt_config->endArray();
1163 qt_config->beginWriteArray(QStringLiteral("ip_ban_list"));
1164 for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) {
1165 qt_config->setArrayIndex(static_cast<int>(i));
1166 WriteSetting(QStringLiteral("ip"),
1167 QString::fromStdString(UISettings::values.multiplayer_ban_list.second[i]));
1168 }
1169 qt_config->endArray();
1170
1171 qt_config->endGroup();
1172}
1173
1174QVariant Config::ReadSetting(const QString& name) const {
1175 return qt_config->value(name);
1176}
1177
1178QVariant Config::ReadSetting(const QString& name, const QVariant& default_value) const {
1179 QVariant result;
1180 if (qt_config->value(name + QStringLiteral("/default"), false).toBool()) {
1181 result = default_value;
1182 } else {
1183 result = qt_config->value(name, default_value);
1184 }
1185 return result;
1186}
1187
1188void Config::WriteSetting(const QString& name, const QVariant& value) {
1189 qt_config->setValue(name, value);
1190}
1191
1192void Config::WriteSetting(const QString& name, const QVariant& value,
1193 const QVariant& default_value) {
1194 qt_config->setValue(name + QStringLiteral("/default"), value == default_value);
1195 qt_config->setValue(name, value);
1196}
1197
1198void Config::WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
1199 bool use_global) {
1200 if (!global) {
1201 qt_config->setValue(name + QStringLiteral("/use_global"), use_global);
1202 }
1203 if (global || !use_global) {
1204 qt_config->setValue(name + QStringLiteral("/default"), value == default_value);
1205 qt_config->setValue(name, value);
1206 }
1207}
1208
1209void Config::Reload() {
1210 ReadValues();
1211 // To apply default value changes
1212 SaveValues();
1213}
1214
1215void Config::Save() {
1216 SaveValues();
1217}
1218
1219void Config::ReadControlPlayerValue(std::size_t player_index) {
1220 qt_config->beginGroup(QStringLiteral("Controls"));
1221 ReadPlayerValue(player_index);
1222 qt_config->endGroup();
1223}
1224
1225void Config::SaveControlPlayerValue(std::size_t player_index) {
1226 qt_config->beginGroup(QStringLiteral("Controls"));
1227 SavePlayerValue(player_index);
1228 qt_config->endGroup();
1229}
1230
1231void Config::ClearControlPlayerValues() {
1232 qt_config->beginGroup(QStringLiteral("Controls"));
1233 // If key is an empty string, all keys in the current group() are removed.
1234 qt_config->remove(QString{});
1235 qt_config->endGroup();
1236}
1237
1238const std::string& Config::GetConfigFilePath() const {
1239 return qt_config_loc;
1240}
1241
1242static auto FindRelevantList(Settings::Category category) {
1243 auto& map = Settings::values.linkage.by_category;
1244 if (map.contains(category)) {
1245 return Settings::values.linkage.by_category[category];
1246 }
1247 return UISettings::values.linkage.by_category[category];
1248}
1249
1250void Config::ReadCategory(Settings::Category category) {
1251 const auto& settings = FindRelevantList(category);
1252 std::for_each(settings.begin(), settings.end(),
1253 [&](const auto& setting) { ReadSettingGeneric(setting); });
1254}
1255
1256void Config::WriteCategory(Settings::Category category) {
1257 const auto& settings = FindRelevantList(category);
1258 std::for_each(settings.begin(), settings.end(),
1259 [&](const auto& setting) { WriteSettingGeneric(setting); });
1260}
1261
1262void Config::ReadSettingGeneric(Settings::BasicSetting* const setting) {
1263 if (!setting->Save() || (!setting->Switchable() && !global)) {
1264 return;
1265 }
1266 const QString name = QString::fromStdString(setting->GetLabel());
1267 const auto default_value =
1268 QVariant::fromValue<QString>(QString::fromStdString(setting->DefaultToString()));
1269
1270 bool use_global = true;
1271 if (setting->Switchable() && !global) {
1272 use_global = qt_config->value(name + QStringLiteral("/use_global"), true).value<bool>();
1273 setting->SetGlobal(use_global);
1274 }
1275
1276 if (global || !use_global) {
1277 const bool is_default =
1278 qt_config->value(name + QStringLiteral("/default"), true).value<bool>();
1279 if (!is_default) {
1280 setting->LoadString(
1281 qt_config->value(name, default_value).value<QString>().toStdString());
1282 } else {
1283 // Empty string resets the Setting to default
1284 setting->LoadString("");
1285 }
1286 }
1287}
1288
1289void Config::WriteSettingGeneric(Settings::BasicSetting* const setting) const {
1290 if (!setting->Save()) {
1291 return;
1292 }
1293 const QVariant value = QVariant::fromValue(QString::fromStdString(setting->ToString()));
1294 const QVariant default_value =
1295 QVariant::fromValue(QString::fromStdString(setting->DefaultToString()));
1296 const QString label = QString::fromStdString(setting->GetLabel());
1297 if (setting->Switchable()) {
1298 if (!global) {
1299 qt_config->setValue(label + QStringLiteral("/use_global"), setting->UsingGlobal());
1300 }
1301 if (global || !setting->UsingGlobal()) {
1302 qt_config->setValue(label + QStringLiteral("/default"), value == default_value);
1303 qt_config->setValue(label, value);
1304 }
1305 } else if (global) {
1306 qt_config->setValue(label + QStringLiteral("/default"), value == default_value);
1307 qt_config->setValue(label, value);
1308 }
1309}
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 @@
1// SPDX-FileCopyrightText: 2014 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <memory>
8#include <string>
9#include <QMetaType>
10#include <QVariant>
11#include "common/settings.h"
12#include "common/settings_enums.h"
13#include "yuzu/uisettings.h"
14
15class QSettings;
16
17namespace Core {
18class System;
19}
20
21class Config {
22public:
23 enum class ConfigType {
24 GlobalConfig,
25 PerGameConfig,
26 InputProfile,
27 };
28
29 explicit Config(const std::string& config_name = "qt-config",
30 ConfigType config_type = ConfigType::GlobalConfig);
31 ~Config();
32
33 void Reload();
34 void Save();
35
36 void ReadControlPlayerValue(std::size_t player_index);
37 void SaveControlPlayerValue(std::size_t player_index);
38 void ClearControlPlayerValues();
39
40 const std::string& GetConfigFilePath() const;
41
42 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
43 static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
44 static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
45 static const std::array<int, 2> default_stick_mod;
46 static const std::array<int, 2> default_ringcon_analogs;
47 static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>
48 default_mouse_buttons;
49 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
50 static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
51 static const std::array<UISettings::Shortcut, 23> default_hotkeys;
52
53 static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map;
54 static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map;
55 static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map;
56 static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map;
57 static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map;
58 static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map;
59
60 static constexpr UISettings::Theme default_theme{
61#ifdef _WIN32
62 UISettings::Theme::DarkColorful
63#else
64 UISettings::Theme::DefaultColorful
65#endif
66 };
67
68private:
69 void Initialize(const std::string& config_name);
70 bool IsCustomConfig();
71
72 void ReadValues();
73 void ReadPlayerValue(std::size_t player_index);
74 void ReadDebugValues();
75 void ReadKeyboardValues();
76 void ReadMouseValues();
77 void ReadTouchscreenValues();
78 void ReadMotionTouchValues();
79 void ReadHidbusValues();
80 void ReadIrCameraValues();
81
82 // Read functions bases off the respective config section names.
83 void ReadAudioValues();
84 void ReadControlValues();
85 void ReadCoreValues();
86 void ReadDataStorageValues();
87 void ReadDebuggingValues();
88 void ReadServiceValues();
89 void ReadDisabledAddOnValues();
90 void ReadMiscellaneousValues();
91 void ReadPathValues();
92 void ReadCpuValues();
93 void ReadRendererValues();
94 void ReadScreenshotValues();
95 void ReadShortcutValues();
96 void ReadSystemValues();
97 void ReadUIValues();
98 void ReadUIGamelistValues();
99 void ReadUILayoutValues();
100 void ReadWebServiceValues();
101 void ReadMultiplayerValues();
102 void ReadNetworkValues();
103
104 void SaveValues();
105 void SavePlayerValue(std::size_t player_index);
106 void SaveDebugValues();
107 void SaveMouseValues();
108 void SaveTouchscreenValues();
109 void SaveMotionTouchValues();
110 void SaveHidbusValues();
111 void SaveIrCameraValues();
112
113 // Save functions based off the respective config section names.
114 void SaveAudioValues();
115 void SaveControlValues();
116 void SaveCoreValues();
117 void SaveDataStorageValues();
118 void SaveDebuggingValues();
119 void SaveNetworkValues();
120 void SaveDisabledAddOnValues();
121 void SaveMiscellaneousValues();
122 void SavePathValues();
123 void SaveCpuValues();
124 void SaveRendererValues();
125 void SaveScreenshotValues();
126 void SaveShortcutValues();
127 void SaveSystemValues();
128 void SaveUIValues();
129 void SaveUIGamelistValues();
130 void SaveUILayoutValues();
131 void SaveWebServiceValues();
132 void SaveMultiplayerValues();
133
134 /**
135 * Reads a setting from the qt_config.
136 *
137 * @param name The setting's identifier
138 * @param default_value The value to use when the setting is not already present in the config
139 */
140 QVariant ReadSetting(const QString& name) const;
141 QVariant ReadSetting(const QString& name, const QVariant& default_value) const;
142
143 /**
144 * Writes a setting to the qt_config.
145 *
146 * @param name The setting's idetentifier
147 * @param value Value of the setting
148 * @param default_value Default of the setting if not present in qt_config
149 * @param use_global Specifies if the custom or global config should be in use, for custom
150 * configs
151 */
152 void WriteSetting(const QString& name, const QVariant& value);
153 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
154 void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value,
155 bool use_global);
156
157 void ReadCategory(Settings::Category category);
158 void WriteCategory(Settings::Category category);
159 void ReadSettingGeneric(Settings::BasicSetting* const setting);
160 void WriteSettingGeneric(Settings::BasicSetting* const setting) const;
161
162 const ConfigType type;
163 std::unique_ptr<QSettings> qt_config;
164 std::string qt_config_loc;
165 const bool global;
166};
167
168// These metatype declarations cannot be in common/settings.h because core is devoid of QT
169Q_DECLARE_METATYPE(Settings::CpuAccuracy);
170Q_DECLARE_METATYPE(Settings::GpuAccuracy);
171Q_DECLARE_METATYPE(Settings::FullscreenMode);
172Q_DECLARE_METATYPE(Settings::NvdecEmulation);
173Q_DECLARE_METATYPE(Settings::ResolutionSetup);
174Q_DECLARE_METATYPE(Settings::ScalingFilter);
175Q_DECLARE_METATYPE(Settings::AntiAliasing);
176Q_DECLARE_METATYPE(Settings::RendererBackend);
177Q_DECLARE_METATYPE(Settings::ShaderBackend);
178Q_DECLARE_METATYPE(Settings::AstcRecompression);
179Q_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 @@
10#include <QStandardItemModel> 10#include <QStandardItemModel>
11#include <QTimer> 11#include <QTimer>
12 12
13#include "common/settings.h"
13#include "input_common/drivers/camera.h" 14#include "input_common/drivers/camera.h"
14#include "input_common/main.h" 15#include "input_common/main.h"
15#include "ui_configure_camera.h" 16#include "ui_configure_camera.h"
16#include "yuzu/configuration/config.h"
17#include "yuzu/configuration/configure_camera.h" 17#include "yuzu/configuration/configure_camera.h"
18 18
19ConfigureCamera::ConfigureCamera(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) 19ConfigureCamera::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 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "ui_configure.h" 9#include "ui_configure.h"
10#include "vk_device_info.h" 10#include "vk_device_info.h"
11#include "yuzu/configuration/config.h"
12#include "yuzu/configuration/configure_audio.h" 11#include "yuzu/configuration/configure_audio.h"
13#include "yuzu/configuration/configure_cpu.h" 12#include "yuzu/configuration/configure_cpu.h"
14#include "yuzu/configuration/configure_debug_tab.h" 13#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 @@
9#include "core/hid/emulated_controller.h" 9#include "core/hid/emulated_controller.h"
10#include "core/hid/hid_core.h" 10#include "core/hid/hid_core.h"
11 11
12#include "frontend_common/config.h"
12#include "ui_configure_hotkeys.h" 13#include "ui_configure_hotkeys.h"
13#include "yuzu/configuration/config.h"
14#include "yuzu/configuration/configure_hotkeys.h" 14#include "yuzu/configuration/configure_hotkeys.h"
15#include "yuzu/hotkeys.h" 15#include "yuzu/hotkeys.h"
16#include "yuzu/uisettings.h"
16#include "yuzu/util/sequence_dialog/sequence_dialog.h" 17#include "yuzu/util/sequence_dialog/sequence_dialog.h"
17 18
18constexpr int name_column = 0; 19constexpr int name_column = 0;
@@ -62,18 +63,21 @@ ConfigureHotkeys::~ConfigureHotkeys() = default;
62 63
63void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { 64void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) {
64 for (const auto& group : registry.hotkey_groups) { 65 for (const auto& group : registry.hotkey_groups) {
66 QString parent_item_data = QString::fromStdString(group.first);
65 auto* parent_item = 67 auto* parent_item =
66 new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(group.first))); 68 new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(parent_item_data)));
67 parent_item->setEditable(false); 69 parent_item->setEditable(false);
68 parent_item->setData(group.first); 70 parent_item->setData(parent_item_data);
69 for (const auto& hotkey : group.second) { 71 for (const auto& hotkey : group.second) {
70 auto* action = 72 QString hotkey_action_data = QString::fromStdString(hotkey.first);
71 new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(hotkey.first))); 73 auto* action = new QStandardItem(
74 QCoreApplication::translate("Hotkeys", qPrintable(hotkey_action_data)));
72 auto* keyseq = 75 auto* keyseq =
73 new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); 76 new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText));
74 auto* controller_keyseq = new QStandardItem(hotkey.second.controller_keyseq); 77 auto* controller_keyseq =
78 new QStandardItem(QString::fromStdString(hotkey.second.controller_keyseq));
75 action->setEditable(false); 79 action->setEditable(false);
76 action->setData(hotkey.first); 80 action->setData(hotkey_action_data);
77 keyseq->setEditable(false); 81 keyseq->setEditable(false);
78 controller_keyseq->setEditable(false); 82 controller_keyseq->setEditable(false);
79 parent_item->appendRow({action, keyseq, controller_keyseq}); 83 parent_item->appendRow({action, keyseq, controller_keyseq});
@@ -301,13 +305,13 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) {
301 const QStandardItem* controller_keyseq = 305 const QStandardItem* controller_keyseq =
302 parent->child(key_column_id, controller_column); 306 parent->child(key_column_id, controller_column);
303 for (auto& [group, sub_actions] : registry.hotkey_groups) { 307 for (auto& [group, sub_actions] : registry.hotkey_groups) {
304 if (group != parent->data()) 308 if (group != parent->data().toString().toStdString())
305 continue; 309 continue;
306 for (auto& [action_name, hotkey] : sub_actions) { 310 for (auto& [action_name, hotkey] : sub_actions) {
307 if (action_name != action->data()) 311 if (action_name != action->data().toString().toStdString())
308 continue; 312 continue;
309 hotkey.keyseq = QKeySequence(keyseq->text()); 313 hotkey.keyseq = QKeySequence(keyseq->text());
310 hotkey.controller_keyseq = controller_keyseq->text(); 314 hotkey.controller_keyseq = controller_keyseq->text().toStdString();
311 } 315 }
312 } 316 }
313 } 317 }
@@ -319,7 +323,7 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) {
319void ConfigureHotkeys::RestoreDefaults() { 323void ConfigureHotkeys::RestoreDefaults() {
320 for (int r = 0; r < model->rowCount(); ++r) { 324 for (int r = 0; r < model->rowCount(); ++r) {
321 const QStandardItem* parent = model->item(r, 0); 325 const QStandardItem* parent = model->item(r, 0);
322 const int hotkey_size = static_cast<int>(Config::default_hotkeys.size()); 326 const int hotkey_size = static_cast<int>(UISettings::default_hotkeys.size());
323 327
324 if (hotkey_size != parent->rowCount()) { 328 if (hotkey_size != parent->rowCount()) {
325 QMessageBox::warning(this, tr("Invalid hotkey settings"), 329 QMessageBox::warning(this, tr("Invalid hotkey settings"),
@@ -330,10 +334,11 @@ void ConfigureHotkeys::RestoreDefaults() {
330 for (int r2 = 0; r2 < parent->rowCount(); ++r2) { 334 for (int r2 = 0; r2 < parent->rowCount(); ++r2) {
331 model->item(r, 0) 335 model->item(r, 0)
332 ->child(r2, hotkey_column) 336 ->child(r2, hotkey_column)
333 ->setText(Config::default_hotkeys[r2].shortcut.keyseq); 337 ->setText(QString::fromStdString(UISettings::default_hotkeys[r2].shortcut.keyseq));
334 model->item(r, 0) 338 model->item(r, 0)
335 ->child(r2, controller_column) 339 ->child(r2, controller_column)
336 ->setText(Config::default_hotkeys[r2].shortcut.controller_keyseq); 340 ->setText(QString::fromStdString(
341 UISettings::default_hotkeys[r2].shortcut.controller_keyseq));
337 } 342 }
338 } 343 }
339} 344}
@@ -379,7 +384,7 @@ void ConfigureHotkeys::PopupContextMenu(const QPoint& menu_location) {
379 384
380void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) { 385void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) {
381 const QString& default_key_sequence = 386 const QString& default_key_sequence =
382 Config::default_hotkeys[index.row()].shortcut.controller_keyseq; 387 QString::fromStdString(UISettings::default_hotkeys[index.row()].shortcut.controller_keyseq);
383 const auto [key_sequence_used, used_action] = IsUsedControllerKey(default_key_sequence); 388 const auto [key_sequence_used, used_action] = IsUsedControllerKey(default_key_sequence);
384 389
385 if (key_sequence_used && default_key_sequence != model->data(index).toString()) { 390 if (key_sequence_used && default_key_sequence != model->data(index).toString()) {
@@ -393,7 +398,8 @@ void ConfigureHotkeys::RestoreControllerHotkey(QModelIndex index) {
393 398
394void ConfigureHotkeys::RestoreHotkey(QModelIndex index) { 399void ConfigureHotkeys::RestoreHotkey(QModelIndex index) {
395 const QKeySequence& default_key_sequence = QKeySequence::fromString( 400 const QKeySequence& default_key_sequence = QKeySequence::fromString(
396 Config::default_hotkeys[index.row()].shortcut.keyseq, QKeySequence::NativeText); 401 QString::fromStdString(UISettings::default_hotkeys[index.row()].shortcut.keyseq),
402 QKeySequence::NativeText);
397 const auto [key_sequence_used, used_action] = IsUsedKey(default_key_sequence); 403 const auto [key_sequence_used, used_action] = IsUsedKey(default_key_sequence);
398 404
399 if (key_sequence_used && default_key_sequence != QKeySequence(model->data(index).toString())) { 405 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 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hid/emulated_controller.h" 6#include "core/hid/emulated_controller.h"
7#include "core/hid/hid_core.h" 7#include "core/hid/hid_core.h"
8#include "frontend_common/config.h"
8#include "ui_configure_input_per_game.h" 9#include "ui_configure_input_per_game.h"
9#include "yuzu/configuration/config.h"
10#include "yuzu/configuration/configure_input_per_game.h" 10#include "yuzu/configuration/configure_input_per_game.h"
11#include "yuzu/configuration/input_profiles.h" 11#include "yuzu/configuration/input_profiles.h"
12 12
13ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, Config* config_, 13ConfigureInputPerGame::ConfigureInputPerGame(Core::System& system_, QtConfig* config_,
14 QWidget* parent) 14 QWidget* parent)
15 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPerGame>()), 15 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputPerGame>()),
16 profiles(std::make_unique<InputProfiles>()), system{system_}, config{config_} { 16 profiles(std::make_unique<InputProfiles>()), system{system_}, config{config_} {
@@ -110,6 +110,6 @@ void ConfigureInputPerGame::SaveConfiguration() {
110 // Clear all controls from the config in case the user reverted back to globals 110 // Clear all controls from the config in case the user reverted back to globals
111 config->ClearControlPlayerValues(); 111 config->ClearControlPlayerValues();
112 for (size_t index = 0; index < Settings::values.players.GetValue().size(); ++index) { 112 for (size_t index = 0; index < Settings::values.players.GetValue().size(); ++index) {
113 config->SaveControlPlayerValue(index); 113 config->SaveQtControlPlayerValues(index);
114 } 114 }
115} 115}
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 @@
9 9
10#include "ui_configure_input_per_game.h" 10#include "ui_configure_input_per_game.h"
11#include "yuzu/configuration/input_profiles.h" 11#include "yuzu/configuration/input_profiles.h"
12#include "yuzu/configuration/qt_config.h"
12 13
13class QComboBox; 14class QComboBox;
14 15
@@ -22,7 +23,7 @@ class ConfigureInputPerGame : public QWidget {
22 Q_OBJECT 23 Q_OBJECT
23 24
24public: 25public:
25 explicit ConfigureInputPerGame(Core::System& system_, Config* config_, 26 explicit ConfigureInputPerGame(Core::System& system_, QtConfig* config_,
26 QWidget* parent = nullptr); 27 QWidget* parent = nullptr);
27 28
28 /// Load and Save configurations to settings file. 29 /// Load and Save configurations to settings file.
@@ -41,5 +42,5 @@ private:
41 std::array<QComboBox*, 8> profile_comboboxes; 42 std::array<QComboBox*, 8> profile_comboboxes;
42 43
43 Core::System& system; 44 Core::System& system;
44 Config* config; 45 QtConfig* config;
45}; 46};
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 @@
12#include <QTimer> 12#include <QTimer>
13#include "common/assert.h" 13#include "common/assert.h"
14#include "common/param_package.h" 14#include "common/param_package.h"
15#include "configuration/qt_config.h"
15#include "core/hid/emulated_controller.h" 16#include "core/hid/emulated_controller.h"
16#include "core/hid/hid_core.h" 17#include "core/hid/hid_core.h"
17#include "core/hid/hid_types.h" 18#include "core/hid/hid_types.h"
19#include "frontend_common/config.h"
18#include "input_common/drivers/keyboard.h" 20#include "input_common/drivers/keyboard.h"
19#include "input_common/drivers/mouse.h" 21#include "input_common/drivers/mouse.h"
20#include "input_common/main.h" 22#include "input_common/main.h"
21#include "ui_configure_input_player.h" 23#include "ui_configure_input_player.h"
22#include "yuzu/bootmanager.h" 24#include "yuzu/bootmanager.h"
23#include "yuzu/configuration/config.h"
24#include "yuzu/configuration/configure_input_player.h" 25#include "yuzu/configuration/configure_input_player.h"
25#include "yuzu/configuration/configure_input_player_widget.h" 26#include "yuzu/configuration/configure_input_player_widget.h"
26#include "yuzu/configuration/configure_mouse_panning.h" 27#include "yuzu/configuration/configure_mouse_panning.h"
@@ -1397,25 +1398,25 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
1397 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { 1398 for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
1398 emulated_controller->SetButtonParam( 1399 emulated_controller->SetButtonParam(
1399 button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( 1400 button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
1400 Config::default_buttons[button_id])}); 1401 QtConfig::default_buttons[button_id])});
1401 } 1402 }
1402 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { 1403 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
1403 Common::ParamPackage analog_param{}; 1404 Common::ParamPackage analog_param{};
1404 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { 1405 for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
1405 Common::ParamPackage params{InputCommon::GenerateKeyboardParam( 1406 Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
1406 Config::default_analogs[analog_id][sub_button_id])}; 1407 QtConfig::default_analogs[analog_id][sub_button_id])};
1407 SetAnalogParam(params, analog_param, analog_sub_buttons[sub_button_id]); 1408 SetAnalogParam(params, analog_param, analog_sub_buttons[sub_button_id]);
1408 } 1409 }
1409 1410
1410 analog_param.Set("modifier", InputCommon::GenerateKeyboardParam( 1411 analog_param.Set("modifier", InputCommon::GenerateKeyboardParam(
1411 Config::default_stick_mod[analog_id])); 1412 QtConfig::default_stick_mod[analog_id]));
1412 emulated_controller->SetStickParam(analog_id, analog_param); 1413 emulated_controller->SetStickParam(analog_id, analog_param);
1413 } 1414 }
1414 1415
1415 for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { 1416 for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
1416 emulated_controller->SetMotionParam( 1417 emulated_controller->SetMotionParam(
1417 motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( 1418 motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam(
1418 Config::default_motions[motion_id])}); 1419 QtConfig::default_motions[motion_id])});
1419 } 1420 }
1420 1421
1421 // If mouse is selected we want to override with mappings from the driver 1422 // 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 @@
25#include "core/file_sys/patch_manager.h" 25#include "core/file_sys/patch_manager.h"
26#include "core/file_sys/xts_archive.h" 26#include "core/file_sys/xts_archive.h"
27#include "core/loader/loader.h" 27#include "core/loader/loader.h"
28#include "frontend_common/config.h"
28#include "ui_configure_per_game.h" 29#include "ui_configure_per_game.h"
29#include "yuzu/configuration/config.h"
30#include "yuzu/configuration/configuration_shared.h" 30#include "yuzu/configuration/configuration_shared.h"
31#include "yuzu/configuration/configure_audio.h" 31#include "yuzu/configuration/configure_audio.h"
32#include "yuzu/configuration/configure_cpu.h" 32#include "yuzu/configuration/configure_cpu.h"
@@ -50,8 +50,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
50 const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); 50 const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name));
51 const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) 51 const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename())
52 : fmt::format("{:016X}", title_id); 52 : fmt::format("{:016X}", title_id);
53 game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig); 53 game_config = std::make_unique<QtConfig>(config_file_name, Config::ConfigType::PerGameConfig);
54
55 addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this); 54 addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this);
56 audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this); 55 audio_tab = std::make_unique<ConfigureAudio>(system_, tab_group, *builder, this);
57 cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this); 56 cpu_tab = std::make_unique<ConfigureCpu>(system_, tab_group, *builder, this);
@@ -108,7 +107,7 @@ void ConfigurePerGame::ApplyConfiguration() {
108 system.ApplySettings(); 107 system.ApplySettings();
109 Settings::LogSettings(); 108 Settings::LogSettings();
110 109
111 game_config->Save(); 110 game_config->SaveAllValues();
112} 111}
113 112
114void ConfigurePerGame::changeEvent(QEvent* event) { 113void 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 @@
12 12
13#include "configuration/shared_widget.h" 13#include "configuration/shared_widget.h"
14#include "core/file_sys/vfs_types.h" 14#include "core/file_sys/vfs_types.h"
15#include "frontend_common/config.h"
15#include "vk_device_info.h" 16#include "vk_device_info.h"
16#include "yuzu/configuration/config.h"
17#include "yuzu/configuration/configuration_shared.h" 17#include "yuzu/configuration/configuration_shared.h"
18#include "yuzu/configuration/qt_config.h"
18#include "yuzu/configuration/shared_translation.h" 19#include "yuzu/configuration/shared_translation.h"
19 20
20namespace Core { 21namespace Core {
@@ -72,7 +73,7 @@ private:
72 73
73 QGraphicsScene* scene; 74 QGraphicsScene* scene;
74 75
75 std::unique_ptr<Config> game_config; 76 std::unique_ptr<QtConfig> game_config;
76 77
77 Core::System& system; 78 Core::System& system;
78 std::unique_ptr<ConfigurationShared::Builder> builder; 79 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 @@
19#include "core/file_sys/xts_archive.h" 19#include "core/file_sys/xts_archive.h"
20#include "core/loader/loader.h" 20#include "core/loader/loader.h"
21#include "ui_configure_per_game_addons.h" 21#include "ui_configure_per_game_addons.h"
22#include "yuzu/configuration/config.h"
23#include "yuzu/configuration/configure_input.h" 22#include "yuzu/configuration/configure_input.h"
24#include "yuzu/configuration/configure_per_game_addons.h" 23#include "yuzu/configuration/configure_per_game_addons.h"
25#include "yuzu/uisettings.h" 24#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 @@
8#include <QTimer> 8#include <QTimer>
9#include <fmt/format.h> 9#include <fmt/format.h>
10 10
11#include "configuration/qt_config.h"
11#include "core/hid/emulated_controller.h" 12#include "core/hid/emulated_controller.h"
12#include "core/hid/hid_core.h" 13#include "core/hid/hid_core.h"
13#include "input_common/drivers/keyboard.h" 14#include "input_common/drivers/keyboard.h"
@@ -15,7 +16,6 @@
15#include "input_common/main.h" 16#include "input_common/main.h"
16#include "ui_configure_ringcon.h" 17#include "ui_configure_ringcon.h"
17#include "yuzu/bootmanager.h" 18#include "yuzu/bootmanager.h"
18#include "yuzu/configuration/config.h"
19#include "yuzu/configuration/configure_ringcon.h" 19#include "yuzu/configuration/configure_ringcon.h"
20 20
21const std::array<std::string, ConfigureRingController::ANALOG_SUB_BUTTONS_NUM> 21const std::array<std::string, ConfigureRingController::ANALOG_SUB_BUTTONS_NUM>
@@ -270,7 +270,7 @@ void ConfigureRingController::LoadConfiguration() {
270 270
271void ConfigureRingController::RestoreDefaults() { 271void ConfigureRingController::RestoreDefaults() {
272 const std::string default_ring_string = InputCommon::GenerateAnalogParamFromKeys( 272 const std::string default_ring_string = InputCommon::GenerateAnalogParamFromKeys(
273 0, 0, Config::default_ringcon_analogs[0], Config::default_ringcon_analogs[1], 0, 0.05f); 273 0, 0, QtConfig::default_ringcon_analogs[0], QtConfig::default_ringcon_analogs[1], 0, 0.05f);
274 emulated_controller->SetRingParam(Common::ParamPackage(default_ring_string)); 274 emulated_controller->SetRingParam(Common::ParamPackage(default_ring_string));
275 UpdateUI(); 275 UpdateUI();
276} 276}
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 @@
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/service/time/time_manager.h" 17#include "core/hle/service/time/time_manager.h"
18#include "ui_configure_system.h" 18#include "ui_configure_system.h"
19#include "yuzu/configuration/config.h"
20#include "yuzu/configuration/configuration_shared.h" 19#include "yuzu/configuration/configuration_shared.h"
21#include "yuzu/configuration/configure_system.h" 20#include "yuzu/configuration/configure_system.h"
22#include "yuzu/configuration/shared_widget.h" 21#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 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <memory> 4#include <memory>
5#include "common/settings.h"
5#include "ui_configure_touchscreen_advanced.h" 6#include "ui_configure_touchscreen_advanced.h"
6#include "yuzu/configuration/config.h"
7#include "yuzu/configuration/configure_touchscreen_advanced.h" 7#include "yuzu/configuration/configure_touchscreen_advanced.h"
8 8
9ConfigureTouchscreenAdvanced::ConfigureTouchscreenAdvanced(QWidget* parent) 9ConfigureTouchscreenAdvanced::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;
164 164
165void ConfigureUi::ApplyConfiguration() { 165void ConfigureUi::ApplyConfiguration() {
166 UISettings::values.theme = 166 UISettings::values.theme =
167 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); 167 ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString().toStdString();
168 UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); 168 UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
169 UISettings::values.show_compat = ui->show_compat->isChecked(); 169 UISettings::values.show_compat = ui->show_compat->isChecked();
170 UISettings::values.show_size = ui->show_size->isChecked(); 170 UISettings::values.show_size = ui->show_size->isChecked();
@@ -191,9 +191,10 @@ void ConfigureUi::RequestGameListUpdate() {
191} 191}
192 192
193void ConfigureUi::SetConfiguration() { 193void ConfigureUi::SetConfiguration() {
194 ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); 194 ui->theme_combobox->setCurrentIndex(
195 ui->theme_combobox->findData(QString::fromStdString(UISettings::values.theme)));
195 ui->language_combobox->setCurrentIndex( 196 ui->language_combobox->setCurrentIndex(
196 ui->language_combobox->findData(UISettings::values.language)); 197 ui->language_combobox->findData(QString::fromStdString(UISettings::values.language)));
197 ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue()); 198 ui->show_add_ons->setChecked(UISettings::values.show_add_ons.GetValue());
198 ui->show_compat->setChecked(UISettings::values.show_compat.GetValue()); 199 ui->show_compat->setChecked(UISettings::values.show_compat.GetValue());
199 ui->show_size->setChecked(UISettings::values.show_size.GetValue()); 200 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 @@
5 5
6#include "common/fs/fs.h" 6#include "common/fs/fs.h"
7#include "common/fs/path_util.h" 7#include "common/fs/path_util.h"
8#include "yuzu/configuration/config.h" 8#include "frontend_common/config.h"
9#include "yuzu/configuration/input_profiles.h" 9#include "yuzu/configuration/input_profiles.h"
10 10
11namespace FS = Common::FS; 11namespace FS = Common::FS;
@@ -44,7 +44,7 @@ InputProfiles::InputProfiles() {
44 if (IsINI(filename) && IsProfileNameValid(name_without_ext)) { 44 if (IsINI(filename) && IsProfileNameValid(name_without_ext)) {
45 map_profiles.insert_or_assign( 45 map_profiles.insert_or_assign(
46 name_without_ext, 46 name_without_ext,
47 std::make_unique<Config>(name_without_ext, Config::ConfigType::InputProfile)); 47 std::make_unique<QtConfig>(name_without_ext, Config::ConfigType::InputProfile));
48 } 48 }
49 49
50 return true; 50 return true;
@@ -85,7 +85,7 @@ bool InputProfiles::CreateProfile(const std::string& profile_name, std::size_t p
85 } 85 }
86 86
87 map_profiles.insert_or_assign( 87 map_profiles.insert_or_assign(
88 profile_name, std::make_unique<Config>(profile_name, Config::ConfigType::InputProfile)); 88 profile_name, std::make_unique<QtConfig>(profile_name, Config::ConfigType::InputProfile));
89 89
90 return SaveProfile(profile_name, player_index); 90 return SaveProfile(profile_name, player_index);
91} 91}
@@ -113,7 +113,7 @@ bool InputProfiles::LoadProfile(const std::string& profile_name, std::size_t pla
113 return false; 113 return false;
114 } 114 }
115 115
116 map_profiles[profile_name]->ReadControlPlayerValue(player_index); 116 map_profiles[profile_name]->ReadQtControlPlayerValues(player_index);
117 return true; 117 return true;
118} 118}
119 119
@@ -122,7 +122,7 @@ bool InputProfiles::SaveProfile(const std::string& profile_name, std::size_t pla
122 return false; 122 return false;
123 } 123 }
124 124
125 map_profiles[profile_name]->SaveControlPlayerValue(player_index); 125 map_profiles[profile_name]->SaveQtControlPlayerValues(player_index);
126 return true; 126 return true;
127} 127}
128 128
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 @@
6#include <string> 6#include <string>
7#include <unordered_map> 7#include <unordered_map>
8 8
9#include "configuration/qt_config.h"
10
9namespace Core { 11namespace Core {
10class System; 12class System;
11} 13}
@@ -30,5 +32,5 @@ public:
30private: 32private:
31 bool ProfileExistsInMap(const std::string& profile_name) const; 33 bool ProfileExistsInMap(const std::string& profile_name) const;
32 34
33 std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles; 35 std::unordered_map<std::string, std::unique_ptr<QtConfig>> map_profiles;
34}; 36};
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "input_common/main.h"
5#include "qt_config.h"
6#include "uisettings.h"
7
8const std::array<int, Settings::NativeButton::NumButtons> QtConfig::default_buttons = {
9 Qt::Key_C, Qt::Key_X, Qt::Key_V, Qt::Key_Z, Qt::Key_F,
10 Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T,
11 Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right,
12 Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0,
13 Qt::Key_Q, Qt::Key_E,
14};
15
16const std::array<int, Settings::NativeMotion::NumMotions> QtConfig::default_motions = {
17 Qt::Key_7,
18 Qt::Key_8,
19};
20
21const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> QtConfig::default_analogs{{
22 {
23 Qt::Key_W,
24 Qt::Key_S,
25 Qt::Key_A,
26 Qt::Key_D,
27 },
28 {
29 Qt::Key_I,
30 Qt::Key_K,
31 Qt::Key_J,
32 Qt::Key_L,
33 },
34}};
35
36const std::array<int, 2> QtConfig::default_stick_mod = {
37 Qt::Key_Shift,
38 0,
39};
40
41const std::array<int, 2> QtConfig::default_ringcon_analogs{{
42 Qt::Key_A,
43 Qt::Key_D,
44}};
45
46QtConfig::QtConfig(const std::string& config_name, const ConfigType config_type)
47 : Config(config_type) {
48 Initialize(config_name);
49 if (config_type != ConfigType::InputProfile) {
50 ReadQtValues();
51 SaveQtValues();
52 }
53}
54
55QtConfig::~QtConfig() {
56 if (global) {
57 QtConfig::SaveAllValues();
58 }
59}
60
61void QtConfig::ReloadAllValues() {
62 Reload();
63 ReadQtValues();
64 SaveQtValues();
65}
66
67void QtConfig::SaveAllValues() {
68 Save();
69 SaveQtValues();
70}
71
72void QtConfig::ReadQtValues() {
73 if (global) {
74 ReadUIValues();
75 }
76 ReadQtControlValues();
77}
78
79void QtConfig::ReadQtPlayerValues(const std::size_t player_index) {
80 std::string player_prefix;
81 if (type != ConfigType::InputProfile) {
82 player_prefix.append("player_").append(ToString(player_index)).append("_");
83 }
84
85 auto& player = Settings::values.players.GetValue()[player_index];
86 if (IsCustomConfig()) {
87 const auto profile_name =
88 ReadStringSetting(std::string(player_prefix).append("profile_name"));
89 if (profile_name.empty()) {
90 // Use the global input config
91 player = Settings::values.players.GetValue(true)[player_index];
92 return;
93 }
94 }
95
96 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
97 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
98 auto& player_buttons = player.buttons[i];
99
100 player_buttons = ReadStringSetting(
101 std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param);
102 if (player_buttons.empty()) {
103 player_buttons = default_param;
104 }
105 }
106
107 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
108 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
109 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
110 default_analogs[i][3], default_stick_mod[i], 0.5f);
111 auto& player_analogs = player.analogs[i];
112
113 player_analogs = ReadStringSetting(
114 std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param);
115 if (player_analogs.empty()) {
116 player_analogs = default_param;
117 }
118 }
119
120 for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
121 const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
122 auto& player_motions = player.motions[i];
123
124 player_motions = ReadStringSetting(
125 std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param);
126 if (player_motions.empty()) {
127 player_motions = default_param;
128 }
129 }
130}
131
132void QtConfig::ReadHidbusValues() {
133 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
134 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
135 auto& ringcon_analogs = Settings::values.ringcon_analogs;
136
137 ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param);
138 if (ringcon_analogs.empty()) {
139 ringcon_analogs = default_param;
140 }
141}
142
143void QtConfig::ReadDebugControlValues() {
144 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
145 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
146 auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i];
147
148 debug_pad_buttons = ReadStringSetting(
149 std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param);
150 if (debug_pad_buttons.empty()) {
151 debug_pad_buttons = default_param;
152 }
153 }
154
155 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
156 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
157 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
158 default_analogs[i][3], default_stick_mod[i], 0.5f);
159 auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
160
161 debug_pad_analogs = ReadStringSetting(
162 std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param);
163 if (debug_pad_analogs.empty()) {
164 debug_pad_analogs = default_param;
165 }
166 }
167}
168
169void QtConfig::ReadQtControlValues() {
170 BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
171
172 Settings::values.players.SetGlobal(!IsCustomConfig());
173 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
174 ReadQtPlayerValues(p);
175 }
176 if (IsCustomConfig()) {
177 EndGroup();
178 return;
179 }
180 ReadDebugControlValues();
181 ReadHidbusValues();
182
183 EndGroup();
184}
185
186void QtConfig::ReadPathValues() {
187 BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
188
189 UISettings::values.roms_path = ReadStringSetting(std::string("romsPath"));
190 UISettings::values.symbols_path = ReadStringSetting(std::string("symbolsPath"));
191 UISettings::values.game_dir_deprecated =
192 ReadStringSetting(std::string("gameListRootDir"), std::string("."));
193 UISettings::values.game_dir_deprecated_deepscan =
194 ReadBooleanSetting(std::string("gameListDeepScan"), std::make_optional(false));
195
196 const int gamedirs_size = BeginArray(std::string("gamedirs"));
197 for (int i = 0; i < gamedirs_size; ++i) {
198 SetArrayIndex(i);
199 UISettings::GameDir game_dir;
200 game_dir.path = ReadStringSetting(std::string("path"));
201 game_dir.deep_scan =
202 ReadBooleanSetting(std::string("deep_scan"), std::make_optional(false));
203 game_dir.expanded = ReadBooleanSetting(std::string("expanded"), std::make_optional(true));
204 UISettings::values.game_dirs.append(game_dir);
205 }
206 EndArray();
207
208 // Create NAND and SD card directories if empty, these are not removable through the UI,
209 // also carries over old game list settings if present
210 if (UISettings::values.game_dirs.empty()) {
211 UISettings::GameDir game_dir;
212 game_dir.path = std::string("SDMC");
213 game_dir.expanded = true;
214 UISettings::values.game_dirs.append(game_dir);
215 game_dir.path = std::string("UserNAND");
216 UISettings::values.game_dirs.append(game_dir);
217 game_dir.path = std::string("SysNAND");
218 UISettings::values.game_dirs.append(game_dir);
219 if (UISettings::values.game_dir_deprecated != std::string(".")) {
220 game_dir.path = UISettings::values.game_dir_deprecated;
221 game_dir.deep_scan = UISettings::values.game_dir_deprecated_deepscan;
222 UISettings::values.game_dirs.append(game_dir);
223 }
224 }
225 UISettings::values.recent_files =
226 QString::fromStdString(ReadStringSetting(std::string("recentFiles")))
227 .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive);
228 UISettings::values.language = ReadStringSetting(std::string("language"), std::string(""));
229
230 EndGroup();
231}
232
233void QtConfig::ReadShortcutValues() {
234 BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts));
235
236 for (const auto& [name, group, shortcut] : UISettings::default_hotkeys) {
237 BeginGroup(group);
238 BeginGroup(name);
239
240 // No longer using ReadSetting for shortcut.second as it inaccurately returns a value of 1
241 // for WidgetWithChildrenShortcut which is a value of 3. Needed to fix shortcuts the open
242 // a file dialog in windowed mode
243 UISettings::values.shortcuts.push_back(
244 {name,
245 group,
246 {ReadStringSetting(std::string("KeySeq"), shortcut.keyseq),
247 ReadStringSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq),
248 shortcut.context,
249 ReadBooleanSetting(std::string("Repeat"), std::optional(shortcut.repeat))}});
250
251 EndGroup(); // name
252 EndGroup(); // group
253 }
254
255 EndGroup();
256}
257
258void QtConfig::ReadUIValues() {
259 BeginGroup(Settings::TranslateCategory(Settings::Category::Ui));
260
261 UISettings::values.theme = ReadStringSetting(
262 std::string("theme"),
263 std::string(UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second));
264
265 ReadUIGamelistValues();
266 ReadUILayoutValues();
267 ReadPathValues();
268 ReadScreenshotValues();
269 ReadShortcutValues();
270 ReadMultiplayerValues();
271
272 ReadCategory(Settings::Category::Ui);
273 ReadCategory(Settings::Category::UiGeneral);
274
275 EndGroup();
276}
277
278void QtConfig::ReadUIGamelistValues() {
279 BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
280
281 ReadCategory(Settings::Category::UiGameList);
282
283 const int favorites_size = BeginArray("favorites");
284 for (int i = 0; i < favorites_size; i++) {
285 SetArrayIndex(i);
286 UISettings::values.favorited_ids.append(
287 ReadUnsignedIntegerSetting(std::string("program_id")));
288 }
289 EndArray();
290
291 EndGroup();
292}
293
294void QtConfig::ReadUILayoutValues() {
295 BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
296
297 ReadCategory(Settings::Category::UiLayout);
298
299 EndGroup();
300}
301
302void QtConfig::ReadMultiplayerValues() {
303 BeginGroup(Settings::TranslateCategory(Settings::Category::Multiplayer));
304
305 ReadCategory(Settings::Category::Multiplayer);
306
307 // Read ban list back
308 int size = BeginArray(std::string("username_ban_list"));
309 UISettings::values.multiplayer_ban_list.first.resize(size);
310 for (int i = 0; i < size; ++i) {
311 SetArrayIndex(i);
312 UISettings::values.multiplayer_ban_list.first[i] =
313 ReadStringSetting(std::string("username"), std::string(""));
314 }
315 EndArray();
316
317 size = BeginArray(std::string("ip_ban_list"));
318 UISettings::values.multiplayer_ban_list.second.resize(size);
319 for (int i = 0; i < size; ++i) {
320 UISettings::values.multiplayer_ban_list.second[i] =
321 ReadStringSetting("username", std::string(""));
322 }
323 EndArray();
324
325 EndGroup();
326}
327
328void QtConfig::SaveQtValues() {
329 if (global) {
330 SaveUIValues();
331 }
332 SaveQtControlValues();
333
334 WriteToIni();
335}
336
337void QtConfig::SaveQtPlayerValues(const std::size_t player_index) {
338 std::string player_prefix;
339 if (type != ConfigType::InputProfile) {
340 player_prefix = std::string("player_").append(ToString(player_index)).append("_");
341 }
342
343 const auto& player = Settings::values.players.GetValue()[player_index];
344 if (IsCustomConfig() && player.profile_name.empty()) {
345 // No custom profile selected
346 return;
347 }
348
349 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
350 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
351 WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]),
352 player.buttons[i], std::make_optional(default_param));
353 }
354 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
355 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
356 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
357 default_analogs[i][3], default_stick_mod[i], 0.5f);
358 WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]),
359 player.analogs[i], std::make_optional(default_param));
360 }
361 for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
362 const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
363 WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]),
364 player.motions[i], std::make_optional(default_param));
365 }
366}
367
368void QtConfig::SaveDebugControlValues() {
369 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
370 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
371 WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]),
372 Settings::values.debug_pad_buttons[i], std::make_optional(default_param));
373 }
374 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
375 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
376 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
377 default_analogs[i][3], default_stick_mod[i], 0.5f);
378 WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]),
379 Settings::values.debug_pad_analogs[i], std::make_optional(default_param));
380 }
381}
382
383void QtConfig::SaveHidbusValues() {
384 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
385 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
386 WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs,
387 std::make_optional(default_param));
388}
389
390void QtConfig::SaveQtControlValues() {
391 BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
392
393 Settings::values.players.SetGlobal(!IsCustomConfig());
394 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
395 SaveQtPlayerValues(p);
396 }
397 if (IsCustomConfig()) {
398 EndGroup();
399 return;
400 }
401 SaveDebugControlValues();
402 SaveHidbusValues();
403
404 EndGroup();
405}
406
407void QtConfig::SavePathValues() {
408 BeginGroup(Settings::TranslateCategory(Settings::Category::Paths));
409
410 WriteSetting(std::string("romsPath"), UISettings::values.roms_path);
411 WriteSetting(std::string("symbolsPath"), UISettings::values.symbols_path);
412 BeginArray(std::string("gamedirs"));
413 for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) {
414 SetArrayIndex(i);
415 const auto& game_dir = UISettings::values.game_dirs[i];
416 WriteSetting(std::string("path"), game_dir.path);
417 WriteSetting(std::string("deep_scan"), game_dir.deep_scan, std::make_optional(false));
418 WriteSetting(std::string("expanded"), game_dir.expanded, std::make_optional(true));
419 }
420 EndArray();
421
422 WriteSetting(std::string("recentFiles"),
423 UISettings::values.recent_files.join(QStringLiteral(", ")).toStdString());
424 WriteSetting(std::string("language"), UISettings::values.language);
425
426 EndGroup();
427}
428
429void QtConfig::SaveShortcutValues() {
430 BeginGroup(Settings::TranslateCategory(Settings::Category::Shortcuts));
431
432 // Lengths of UISettings::values.shortcuts & default_hotkeys are same.
433 // However, their ordering must also be the same.
434 for (std::size_t i = 0; i < UISettings::default_hotkeys.size(); i++) {
435 const auto& [name, group, shortcut] = UISettings::values.shortcuts[i];
436 const auto& default_hotkey = UISettings::default_hotkeys[i].shortcut;
437
438 BeginGroup(group);
439 BeginGroup(name);
440
441 WriteSetting(std::string("KeySeq"), shortcut.keyseq,
442 std::make_optional(default_hotkey.keyseq));
443 WriteSetting(std::string("Controller_KeySeq"), shortcut.controller_keyseq,
444 std::make_optional(default_hotkey.controller_keyseq));
445 WriteSetting(std::string("Context"), shortcut.context,
446 std::make_optional(default_hotkey.context));
447 WriteSetting(std::string("Repeat"), shortcut.repeat,
448 std::make_optional(default_hotkey.repeat));
449
450 EndGroup(); // name
451 EndGroup(); // group
452 }
453
454 EndGroup();
455}
456
457void QtConfig::SaveUIValues() {
458 BeginGroup(Settings::TranslateCategory(Settings::Category::Ui));
459
460 WriteCategory(Settings::Category::Ui);
461 WriteCategory(Settings::Category::UiGeneral);
462
463 WriteSetting(std::string("theme"), UISettings::values.theme,
464 std::make_optional(std::string(
465 UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second)));
466
467 SaveUIGamelistValues();
468 SaveUILayoutValues();
469 SavePathValues();
470 SaveScreenshotValues();
471 SaveShortcutValues();
472 SaveMultiplayerValues();
473
474 EndGroup();
475}
476
477void QtConfig::SaveUIGamelistValues() {
478 BeginGroup(Settings::TranslateCategory(Settings::Category::UiGameList));
479
480 WriteCategory(Settings::Category::UiGameList);
481
482 BeginArray(std::string("favorites"));
483 for (int i = 0; i < UISettings::values.favorited_ids.size(); i++) {
484 SetArrayIndex(i);
485 WriteSetting(std::string("program_id"), UISettings::values.favorited_ids[i]);
486 }
487 EndArray(); // favorites
488
489 EndGroup();
490}
491
492void QtConfig::SaveUILayoutValues() {
493 BeginGroup(Settings::TranslateCategory(Settings::Category::UiLayout));
494
495 WriteCategory(Settings::Category::UiLayout);
496
497 EndGroup();
498}
499
500void QtConfig::SaveMultiplayerValues() {
501 BeginGroup(std::string("Multiplayer"));
502
503 WriteCategory(Settings::Category::Multiplayer);
504
505 // Write ban list
506 BeginArray(std::string("username_ban_list"));
507 for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.first.size(); ++i) {
508 SetArrayIndex(static_cast<int>(i));
509 WriteSetting(std::string("username"), UISettings::values.multiplayer_ban_list.first[i]);
510 }
511 EndArray(); // username_ban_list
512
513 BeginArray(std::string("ip_ban_list"));
514 for (std::size_t i = 0; i < UISettings::values.multiplayer_ban_list.second.size(); ++i) {
515 SetArrayIndex(static_cast<int>(i));
516 WriteSetting(std::string("ip"), UISettings::values.multiplayer_ban_list.second[i]);
517 }
518 EndArray(); // ip_ban_list
519
520 EndGroup();
521}
522
523std::vector<Settings::BasicSetting*>& QtConfig::FindRelevantList(Settings::Category category) {
524 auto& map = Settings::values.linkage.by_category;
525 if (map.contains(category)) {
526 return Settings::values.linkage.by_category[category];
527 }
528 return UISettings::values.linkage.by_category[category];
529}
530
531void QtConfig::ReadQtControlPlayerValues(std::size_t player_index) {
532 BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
533
534 ReadPlayerValues(player_index);
535 ReadQtPlayerValues(player_index);
536
537 EndGroup();
538}
539
540void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) {
541 BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
542
543 SavePlayerValues(player_index);
544 SaveQtPlayerValues(player_index);
545
546 EndGroup();
547
548 WriteToIni();
549}
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <QMetaType>
7
8#include "frontend_common/config.h"
9
10class QtConfig final : public Config {
11public:
12 explicit QtConfig(const std::string& config_name = "qt-config",
13 ConfigType config_type = ConfigType::GlobalConfig);
14 ~QtConfig() override;
15
16 void ReloadAllValues() override;
17 void SaveAllValues() override;
18
19 void ReadQtControlPlayerValues(std::size_t player_index);
20 void SaveQtControlPlayerValues(std::size_t player_index);
21
22protected:
23 void ReadQtValues();
24 void ReadQtPlayerValues(std::size_t player_index);
25 void ReadQtControlValues();
26 void ReadHidbusValues() override;
27 void ReadDebugControlValues() override;
28 void ReadPathValues() override;
29 void ReadShortcutValues() override;
30 void ReadUIValues() override;
31 void ReadUIGamelistValues() override;
32 void ReadUILayoutValues() override;
33 void ReadMultiplayerValues() override;
34
35 void SaveQtValues();
36 void SaveQtPlayerValues(std::size_t player_index);
37 void SaveQtControlValues();
38 void SaveHidbusValues() override;
39 void SaveDebugControlValues() override;
40 void SavePathValues() override;
41 void SaveShortcutValues() override;
42 void SaveUIValues() override;
43 void SaveUIGamelistValues() override;
44 void SaveUILayoutValues() override;
45 void SaveMultiplayerValues() override;
46
47 std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
48
49public:
50 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
51 static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
52 static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
53 static const std::array<int, 2> default_stick_mod;
54 static const std::array<int, 2> default_ringcon_analogs;
55};
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 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/time_zone.h"
5#include "yuzu/configuration/shared_translation.h" 4#include "yuzu/configuration/shared_translation.h"
6 5
7#include <map> 6#include <map>
8#include <memory> 7#include <memory>
9#include <tuple> 8#include <tuple>
10#include <utility> 9#include <utility>
10#include <QCoreApplication>
11#include <QWidget> 11#include <QWidget>
12#include "common/settings.h" 12#include "common/settings.h"
13#include "common/settings_enums.h" 13#include "common/settings_enums.h"
14#include "common/settings_setting.h" 14#include "common/settings_setting.h"
15#include "common/time_zone.h"
15#include "yuzu/uisettings.h" 16#include "yuzu/uisettings.h"
16 17
17namespace ConfigurationShared { 18namespace ConfigurationShared {
@@ -21,123 +22,135 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
21 const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); }; 22 const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); };
22 23
23#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \ 24#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \
24 translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{tr((NAME)), tr((TOOLTIP))}}) 25 translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}})
25 26
26 // A setting can be ignored by giving it a blank name 27 // A setting can be ignored by giving it a blank name
27 28
28 // Audio 29 // Audio
29 INSERT(Settings, sink_id, "Output Engine:", ""); 30 INSERT(Settings, sink_id, tr("Output Engine:"), QStringLiteral());
30 INSERT(Settings, audio_output_device_id, "Output Device:", ""); 31 INSERT(Settings, audio_output_device_id, tr("Output Device:"), QStringLiteral());
31 INSERT(Settings, audio_input_device_id, "Input Device:", ""); 32 INSERT(Settings, audio_input_device_id, tr("Input Device:"), QStringLiteral());
32 INSERT(Settings, audio_muted, "Mute audio", ""); 33 INSERT(Settings, audio_muted, tr("Mute audio"), QStringLiteral());
33 INSERT(Settings, volume, "Volume:", ""); 34 INSERT(Settings, volume, tr("Volume:"), QStringLiteral());
34 INSERT(Settings, dump_audio_commands, "", ""); 35 INSERT(Settings, dump_audio_commands, QStringLiteral(), QStringLiteral());
35 INSERT(UISettings, mute_when_in_background, "Mute audio when in background", ""); 36 INSERT(UISettings, mute_when_in_background, tr("Mute audio when in background"),
37 QStringLiteral());
36 38
37 // Core 39 // Core
38 INSERT(Settings, use_multi_core, "Multicore CPU Emulation", ""); 40 INSERT(Settings, use_multi_core, tr("Multicore CPU Emulation"), QStringLiteral());
39 INSERT(Settings, memory_layout_mode, "Memory Layout", ""); 41 INSERT(Settings, memory_layout_mode, tr("Memory Layout"), QStringLiteral());
40 INSERT(Settings, use_speed_limit, "", ""); 42 INSERT(Settings, use_speed_limit, QStringLiteral(), QStringLiteral());
41 INSERT(Settings, speed_limit, "Limit Speed Percent", ""); 43 INSERT(Settings, speed_limit, tr("Limit Speed Percent"), QStringLiteral());
42 44
43 // Cpu 45 // Cpu
44 INSERT(Settings, cpu_accuracy, "Accuracy:", ""); 46 INSERT(Settings, cpu_accuracy, tr("Accuracy:"), QStringLiteral());
45 47
46 // Cpu Debug 48 // Cpu Debug
47 49
48 // Cpu Unsafe 50 // Cpu Unsafe
49 INSERT(Settings, cpuopt_unsafe_unfuse_fma,
50 "Unfuse FMA (improve performance on CPUs without FMA)",
51 "This option improves speed by reducing accuracy of fused-multiply-add instructions on "
52 "CPUs without native FMA support.");
53 INSERT(Settings, cpuopt_unsafe_reduce_fp_error, "Faster FRSQRTE and FRECPE",
54 "This option improves the speed of some approximate floating-point functions by using "
55 "less accurate native approximations.");
56 INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, "Faster ASIMD instructions (32 bits only)",
57 "This option improves the speed of 32 bits ASIMD floating-point functions by running "
58 "with incorrect rounding modes.");
59 INSERT(Settings, cpuopt_unsafe_inaccurate_nan, "Inaccurate NaN handling",
60 "This option improves speed by removing NaN checking. Please note this also reduces "
61 "accuracy of certain floating-point instructions.");
62 INSERT( 51 INSERT(
63 Settings, cpuopt_unsafe_fastmem_check, "Disable address space checks", 52 Settings, cpuopt_unsafe_unfuse_fma,
64 "This option improves speed by eliminating a safety check before every memory read/write " 53 tr("Unfuse FMA (improve performance on CPUs without FMA)"),
65 "in guest. Disabling it may allow a game to read/write the emulator's memory."); 54 tr("This option improves speed by reducing accuracy of fused-multiply-add instructions on "
66 INSERT(Settings, cpuopt_unsafe_ignore_global_monitor, "Ignore global monitor", 55 "CPUs without native FMA support."));
67 "This option improves speed by relying only on the semantics of cmpxchg to ensure " 56 INSERT(
57 Settings, cpuopt_unsafe_reduce_fp_error, tr("Faster FRSQRTE and FRECPE"),
58 tr("This option improves the speed of some approximate floating-point functions by using "
59 "less accurate native approximations."));
60 INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr,
61 tr("Faster ASIMD instructions (32 bits only)"),
62 tr("This option improves the speed of 32 bits ASIMD floating-point functions by running "
63 "with incorrect rounding modes."));
64 INSERT(Settings, cpuopt_unsafe_inaccurate_nan, tr("Inaccurate NaN handling"),
65 tr("This option improves speed by removing NaN checking. Please note this also reduces "
66 "accuracy of certain floating-point instructions."));
67 INSERT(Settings, cpuopt_unsafe_fastmem_check, tr("Disable address space checks"),
68 tr("This option improves speed by eliminating a safety check before every memory "
69 "read/write "
70 "in guest. Disabling it may allow a game to read/write the emulator's memory."));
71 INSERT(
72 Settings, cpuopt_unsafe_ignore_global_monitor, tr("Ignore global monitor"),
73 tr("This option improves speed by relying only on the semantics of cmpxchg to ensure "
68 "safety of exclusive access instructions. Please note this may result in deadlocks and " 74 "safety of exclusive access instructions. Please note this may result in deadlocks and "
69 "other race conditions."); 75 "other race conditions."));
70 76
71 // Renderer 77 // Renderer
72 INSERT(Settings, renderer_backend, "API:", ""); 78 INSERT(Settings, renderer_backend, tr("API:"), QStringLiteral());
73 INSERT(Settings, vulkan_device, "Device:", ""); 79 INSERT(Settings, vulkan_device, tr("Device:"), QStringLiteral());
74 INSERT(Settings, shader_backend, "Shader Backend:", ""); 80 INSERT(Settings, shader_backend, tr("Shader Backend:"), QStringLiteral());
75 INSERT(Settings, resolution_setup, "Resolution:", ""); 81 INSERT(Settings, resolution_setup, tr("Resolution:"), QStringLiteral());
76 INSERT(Settings, scaling_filter, "Window Adapting Filter:", ""); 82 INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral());
77 INSERT(Settings, fsr_sharpening_slider, "FSR Sharpness:", ""); 83 INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), QStringLiteral());
78 INSERT(Settings, anti_aliasing, "Anti-Aliasing Method:", ""); 84 INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), QStringLiteral());
79 INSERT(Settings, fullscreen_mode, "Fullscreen Mode:", ""); 85 INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), QStringLiteral());
80 INSERT(Settings, aspect_ratio, "Aspect Ratio:", ""); 86 INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"), QStringLiteral());
81 INSERT(Settings, use_disk_shader_cache, "Use disk pipeline cache", ""); 87 INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"), QStringLiteral());
82 INSERT(Settings, use_asynchronous_gpu_emulation, "Use asynchronous GPU emulation", ""); 88 INSERT(Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"),
83 INSERT(Settings, nvdec_emulation, "NVDEC emulation:", ""); 89 QStringLiteral());
84 INSERT(Settings, accelerate_astc, "ASTC Decoding Method:", ""); 90 INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"), QStringLiteral());
85 INSERT(Settings, astc_recompression, "ASTC Recompression Method:", ""); 91 INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"), QStringLiteral());
86 INSERT(Settings, vsync_mode, "VSync Mode:", 92 INSERT(Settings, astc_recompression, tr("ASTC Recompression Method:"), QStringLiteral());
87 "FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " 93 INSERT(
94 Settings, vsync_mode, tr("VSync Mode:"),
95 tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
88 "refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from " 96 "refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from "
89 "a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop " 97 "a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop "
90 "frames.\nImmediate (no synchronization) just presents whatever is available and can " 98 "frames.\nImmediate (no synchronization) just presents whatever is available and can "
91 "exhibit tearing."); 99 "exhibit tearing."));
92 INSERT(Settings, bg_red, "", ""); 100 INSERT(Settings, bg_red, QStringLiteral(), QStringLiteral());
93 INSERT(Settings, bg_green, "", ""); 101 INSERT(Settings, bg_green, QStringLiteral(), QStringLiteral());
94 INSERT(Settings, bg_blue, "", ""); 102 INSERT(Settings, bg_blue, QStringLiteral(), QStringLiteral());
95 103
96 // Renderer (Advanced Graphics) 104 // Renderer (Advanced Graphics)
97 INSERT(Settings, async_presentation, "Enable asynchronous presentation (Vulkan only)", ""); 105 INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"),
98 INSERT(Settings, renderer_force_max_clock, "Force maximum clocks (Vulkan only)", 106 QStringLiteral());
99 "Runs work in the background while waiting for graphics commands to keep the GPU from " 107 INSERT(
100 "lowering its clock speed."); 108 Settings, renderer_force_max_clock, tr("Force maximum clocks (Vulkan only)"),
101 INSERT(Settings, max_anisotropy, "Anisotropic Filtering:", ""); 109 tr("Runs work in the background while waiting for graphics commands to keep the GPU from "
102 INSERT(Settings, gpu_accuracy, "Accuracy Level:", ""); 110 "lowering its clock speed."));
103 INSERT(Settings, use_asynchronous_shaders, "Use asynchronous shader building (Hack)", 111 INSERT(Settings, max_anisotropy, tr("Anisotropic Filtering:"), QStringLiteral());
104 "Enables asynchronous shader compilation, which may reduce shader stutter. This feature " 112 INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"), QStringLiteral());
105 "is experimental."); 113 INSERT(
106 INSERT(Settings, use_fast_gpu_time, "Use Fast GPU Time (Hack)", 114 Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"),
107 "Enables Fast GPU Time. This option will force most games to run at their highest " 115 tr("Enables asynchronous shader compilation, which may reduce shader stutter. This feature "
108 "native resolution."); 116 "is experimental."));
109 INSERT(Settings, use_vulkan_driver_pipeline_cache, "Use Vulkan pipeline cache", 117 INSERT(Settings, use_fast_gpu_time, tr("Use Fast GPU Time (Hack)"),
110 "Enables GPU vendor-specific pipeline cache. This option can improve shader loading " 118 tr("Enables Fast GPU Time. This option will force most games to run at their highest "
111 "time significantly in cases where the Vulkan driver does not store pipeline cache " 119 "native resolution."));
112 "files internally."); 120 INSERT(Settings, use_vulkan_driver_pipeline_cache, tr("Use Vulkan pipeline cache"),
113 INSERT(Settings, enable_compute_pipelines, "Enable Compute Pipelines (Intel Vulkan Only)", 121 tr("Enables GPU vendor-specific pipeline cache. This option can improve shader loading "
114 "Enable compute pipelines, required by some games.\nThis setting only exists for Intel " 122 "time significantly in cases where the Vulkan driver does not store pipeline cache "
123 "files internally."));
124 INSERT(
125 Settings, enable_compute_pipelines, tr("Enable Compute Pipelines (Intel Vulkan Only)"),
126 tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel "
115 "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled " 127 "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled "
116 "on all other drivers."); 128 "on all other drivers."));
117 INSERT(Settings, use_reactive_flushing, "Enable Reactive Flushing", 129 INSERT(
118 "Uses reactive flushing instead of predictive flushing, allowing more accurate memory " 130 Settings, use_reactive_flushing, tr("Enable Reactive Flushing"),
119 "syncing."); 131 tr("Uses reactive flushing instead of predictive flushing, allowing more accurate memory "
120 INSERT(Settings, use_video_framerate, "Sync to framerate of video playback", 132 "syncing."));
121 "Run the game at normal speed during video playback, even when the framerate is " 133 INSERT(Settings, use_video_framerate, tr("Sync to framerate of video playback"),
122 "unlocked."); 134 tr("Run the game at normal speed during video playback, even when the framerate is "
123 INSERT(Settings, barrier_feedback_loops, "Barrier feedback loops", 135 "unlocked."));
124 "Improves rendering of transparency effects in specific games."); 136 INSERT(Settings, barrier_feedback_loops, tr("Barrier feedback loops"),
137 tr("Improves rendering of transparency effects in specific games."));
125 138
126 // Renderer (Debug) 139 // Renderer (Debug)
127 140
128 // System 141 // System
129 INSERT(Settings, rng_seed, "RNG Seed", ""); 142 INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral());
130 INSERT(Settings, rng_seed_enabled, "", ""); 143 INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral());
131 INSERT(Settings, device_name, "Device Name", ""); 144 INSERT(Settings, device_name, tr("Device Name"), QStringLiteral());
132 INSERT(Settings, custom_rtc, "Custom RTC", ""); 145 INSERT(Settings, custom_rtc, tr("Custom RTC"), QStringLiteral());
133 INSERT(Settings, custom_rtc_enabled, "", ""); 146 INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral());
134 INSERT(Settings, language_index, 147 INSERT(Settings, language_index, tr("Language:"),
135 "Language:", "Note: this can be overridden when region setting is auto-select"); 148 tr("Note: this can be overridden when region setting is auto-select"));
136 INSERT(Settings, region_index, "Region:", ""); 149 INSERT(Settings, region_index, tr("Region:"), QStringLiteral());
137 INSERT(Settings, time_zone_index, "Time Zone:", ""); 150 INSERT(Settings, time_zone_index, tr("Time Zone:"), QStringLiteral());
138 INSERT(Settings, sound_index, "Sound Output Mode:", ""); 151 INSERT(Settings, sound_index, tr("Sound Output Mode:"), QStringLiteral());
139 INSERT(Settings, use_docked_mode, "Console Mode:", ""); 152 INSERT(Settings, use_docked_mode, tr("Console Mode:"), QStringLiteral());
140 INSERT(Settings, current_user, "", ""); 153 INSERT(Settings, current_user, QStringLiteral(), QStringLiteral());
141 154
142 // Controls 155 // Controls
143 156
@@ -154,11 +167,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
154 // Ui 167 // Ui
155 168
156 // Ui General 169 // Ui General
157 INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", ""); 170 INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"), QStringLiteral());
158 INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", ""); 171 INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"),
159 INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", ""); 172 QStringLiteral());
160 INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", ""); 173 INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"),
161 INSERT(UISettings, controller_applet_disabled, "Disable controller applet", ""); 174 QStringLiteral());
175 INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), QStringLiteral());
176 INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"),
177 QStringLiteral());
162 178
163 // Ui Debugging 179 // Ui Debugging
164 180
@@ -178,140 +194,141 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
178 return parent->tr(text, context); 194 return parent->tr(text, context);
179 }; 195 };
180 196
181#define PAIR(ENUM, VALUE, TRANSLATION) \ 197#define PAIR(ENUM, VALUE, TRANSLATION) {static_cast<u32>(Settings::ENUM::VALUE), (TRANSLATION)}
182 { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION) }
183#define CTX_PAIR(ENUM, VALUE, TRANSLATION, CONTEXT) \
184 { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION, CONTEXT) }
185 198
186 // Intentionally skipping VSyncMode to let the UI fill that one out 199 // Intentionally skipping VSyncMode to let the UI fill that one out
187 200
188 translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(), 201 translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),
189 { 202 {
190 PAIR(AstcDecodeMode, Cpu, "CPU"), 203 PAIR(AstcDecodeMode, Cpu, tr("CPU")),
191 PAIR(AstcDecodeMode, Gpu, "GPU"), 204 PAIR(AstcDecodeMode, Gpu, tr("GPU")),
192 PAIR(AstcDecodeMode, CpuAsynchronous, "CPU Asynchronous"), 205 PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")),
193 }});
194 translations->insert({Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
195 {
196 PAIR(AstcRecompression, Uncompressed, "Uncompressed (Best quality)"),
197 PAIR(AstcRecompression, Bc1, "BC1 (Low quality)"),
198 PAIR(AstcRecompression, Bc3, "BC3 (Medium quality)"),
199 }}); 206 }});
207 translations->insert(
208 {Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
209 {
210 PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")),
211 PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
212 PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
213 }});
200 translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(), 214 translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
201 { 215 {
202#ifdef HAS_OPENGL 216#ifdef HAS_OPENGL
203 PAIR(RendererBackend, OpenGL, "OpenGL"), 217 PAIR(RendererBackend, OpenGL, tr("OpenGL")),
204#endif 218#endif
205 PAIR(RendererBackend, Vulkan, "Vulkan"), 219 PAIR(RendererBackend, Vulkan, tr("Vulkan")),
206 PAIR(RendererBackend, Null, "Null"), 220 PAIR(RendererBackend, Null, tr("Null")),
207 }});
208 translations->insert({Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
209 {
210 PAIR(ShaderBackend, Glsl, "GLSL"),
211 PAIR(ShaderBackend, Glasm, "GLASM (Assembly Shaders, NVIDIA Only)"),
212 PAIR(ShaderBackend, SpirV, "SPIR-V (Experimental, Mesa Only)"),
213 }}); 221 }});
222 translations->insert(
223 {Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
224 {
225 PAIR(ShaderBackend, Glsl, tr("GLSL")),
226 PAIR(ShaderBackend, Glasm, tr("GLASM (Assembly Shaders, NVIDIA Only)")),
227 PAIR(ShaderBackend, SpirV, tr("SPIR-V (Experimental, Mesa Only)")),
228 }});
214 translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(), 229 translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
215 { 230 {
216 PAIR(GpuAccuracy, Normal, "Normal"), 231 PAIR(GpuAccuracy, Normal, tr("Normal")),
217 PAIR(GpuAccuracy, High, "High"), 232 PAIR(GpuAccuracy, High, tr("High")),
218 PAIR(GpuAccuracy, Extreme, "Extreme"), 233 PAIR(GpuAccuracy, Extreme, tr("Extreme")),
219 }});
220 translations->insert({Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
221 {
222 PAIR(CpuAccuracy, Auto, "Auto"),
223 PAIR(CpuAccuracy, Accurate, "Accurate"),
224 PAIR(CpuAccuracy, Unsafe, "Unsafe"),
225 PAIR(CpuAccuracy, Paranoid, "Paranoid (disables most optimizations)"),
226 }}); 234 }});
235 translations->insert(
236 {Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
237 {
238 PAIR(CpuAccuracy, Auto, tr("Auto")),
239 PAIR(CpuAccuracy, Accurate, tr("Accurate")),
240 PAIR(CpuAccuracy, Unsafe, tr("Unsafe")),
241 PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")),
242 }});
227 translations->insert({Settings::EnumMetadata<Settings::FullscreenMode>::Index(), 243 translations->insert({Settings::EnumMetadata<Settings::FullscreenMode>::Index(),
228 { 244 {
229 PAIR(FullscreenMode, Borderless, "Borderless Windowed"), 245 PAIR(FullscreenMode, Borderless, tr("Borderless Windowed")),
230 PAIR(FullscreenMode, Exclusive, "Exclusive Fullscreen"), 246 PAIR(FullscreenMode, Exclusive, tr("Exclusive Fullscreen")),
231 }}); 247 }});
232 translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(), 248 translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(),
233 { 249 {
234 PAIR(NvdecEmulation, Off, "No Video Output"), 250 PAIR(NvdecEmulation, Off, tr("No Video Output")),
235 PAIR(NvdecEmulation, Cpu, "CPU Video Decoding"), 251 PAIR(NvdecEmulation, Cpu, tr("CPU Video Decoding")),
236 PAIR(NvdecEmulation, Gpu, "GPU Video Decoding (Default)"), 252 PAIR(NvdecEmulation, Gpu, tr("GPU Video Decoding (Default)")),
237 }});
238 translations->insert({Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
239 {
240 PAIR(ResolutionSetup, Res1_2X, "0.5X (360p/540p) [EXPERIMENTAL]"),
241 PAIR(ResolutionSetup, Res3_4X, "0.75X (540p/810p) [EXPERIMENTAL]"),
242 PAIR(ResolutionSetup, Res1X, "1X (720p/1080p)"),
243 PAIR(ResolutionSetup, Res3_2X, "1.5X (1080p/1620p) [EXPERIMENTAL]"),
244 PAIR(ResolutionSetup, Res2X, "2X (1440p/2160p)"),
245 PAIR(ResolutionSetup, Res3X, "3X (2160p/3240p)"),
246 PAIR(ResolutionSetup, Res4X, "4X (2880p/4320p)"),
247 PAIR(ResolutionSetup, Res5X, "5X (3600p/5400p)"),
248 PAIR(ResolutionSetup, Res6X, "6X (4320p/6480p)"),
249 PAIR(ResolutionSetup, Res7X, "7X (5040p/7560p)"),
250 PAIR(ResolutionSetup, Res8X, "8X (5760p/8640p)"),
251 }}); 253 }});
254 translations->insert(
255 {Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
256 {
257 PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")),
258 PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")),
259 PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")),
260 PAIR(ResolutionSetup, Res3_2X, tr("1.5X (1080p/1620p) [EXPERIMENTAL]")),
261 PAIR(ResolutionSetup, Res2X, tr("2X (1440p/2160p)")),
262 PAIR(ResolutionSetup, Res3X, tr("3X (2160p/3240p)")),
263 PAIR(ResolutionSetup, Res4X, tr("4X (2880p/4320p)")),
264 PAIR(ResolutionSetup, Res5X, tr("5X (3600p/5400p)")),
265 PAIR(ResolutionSetup, Res6X, tr("6X (4320p/6480p)")),
266 PAIR(ResolutionSetup, Res7X, tr("7X (5040p/7560p)")),
267 PAIR(ResolutionSetup, Res8X, tr("8X (5760p/8640p)")),
268 }});
252 translations->insert({Settings::EnumMetadata<Settings::ScalingFilter>::Index(), 269 translations->insert({Settings::EnumMetadata<Settings::ScalingFilter>::Index(),
253 { 270 {
254 PAIR(ScalingFilter, NearestNeighbor, "Nearest Neighbor"), 271 PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")),
255 PAIR(ScalingFilter, Bilinear, "Bilinear"), 272 PAIR(ScalingFilter, Bilinear, tr("Bilinear")),
256 PAIR(ScalingFilter, Bicubic, "Bicubic"), 273 PAIR(ScalingFilter, Bicubic, tr("Bicubic")),
257 PAIR(ScalingFilter, Gaussian, "Gaussian"), 274 PAIR(ScalingFilter, Gaussian, tr("Gaussian")),
258 PAIR(ScalingFilter, ScaleForce, "ScaleForce"), 275 PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")),
259 PAIR(ScalingFilter, Fsr, "AMD FidelityFX™️ Super Resolution"), 276 PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")),
260 }}); 277 }});
261 translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(), 278 translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(),
262 { 279 {
263 PAIR(AntiAliasing, None, "None"), 280 PAIR(AntiAliasing, None, tr("None")),
264 PAIR(AntiAliasing, Fxaa, "FXAA"), 281 PAIR(AntiAliasing, Fxaa, tr("FXAA")),
265 PAIR(AntiAliasing, Smaa, "SMAA"), 282 PAIR(AntiAliasing, Smaa, tr("SMAA")),
266 }}); 283 }});
267 translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(), 284 translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(),
268 { 285 {
269 PAIR(AspectRatio, R16_9, "Default (16:9)"), 286 PAIR(AspectRatio, R16_9, tr("Default (16:9)")),
270 PAIR(AspectRatio, R4_3, "Force 4:3"), 287 PAIR(AspectRatio, R4_3, tr("Force 4:3")),
271 PAIR(AspectRatio, R21_9, "Force 21:9"), 288 PAIR(AspectRatio, R21_9, tr("Force 21:9")),
272 PAIR(AspectRatio, R16_10, "Force 16:10"), 289 PAIR(AspectRatio, R16_10, tr("Force 16:10")),
273 PAIR(AspectRatio, Stretch, "Stretch to Window"), 290 PAIR(AspectRatio, Stretch, tr("Stretch to Window")),
274 }}); 291 }});
275 translations->insert({Settings::EnumMetadata<Settings::AnisotropyMode>::Index(), 292 translations->insert({Settings::EnumMetadata<Settings::AnisotropyMode>::Index(),
276 { 293 {
277 PAIR(AnisotropyMode, Automatic, "Automatic"), 294 PAIR(AnisotropyMode, Automatic, tr("Automatic")),
278 PAIR(AnisotropyMode, Default, "Default"), 295 PAIR(AnisotropyMode, Default, tr("Default")),
279 PAIR(AnisotropyMode, X2, "2x"), 296 PAIR(AnisotropyMode, X2, tr("2x")),
280 PAIR(AnisotropyMode, X4, "4x"), 297 PAIR(AnisotropyMode, X4, tr("4x")),
281 PAIR(AnisotropyMode, X8, "8x"), 298 PAIR(AnisotropyMode, X8, tr("8x")),
282 PAIR(AnisotropyMode, X16, "16x"), 299 PAIR(AnisotropyMode, X16, tr("16x")),
283 }}); 300 }});
284 translations->insert( 301 translations->insert(
285 {Settings::EnumMetadata<Settings::Language>::Index(), 302 {Settings::EnumMetadata<Settings::Language>::Index(),
286 { 303 {
287 PAIR(Language, Japanese, "Japanese (日本語)"), 304 PAIR(Language, Japanese, tr("Japanese (日本語)")),
288 PAIR(Language, EnglishAmerican, "American English"), 305 PAIR(Language, EnglishAmerican, tr("American English")),
289 PAIR(Language, French, "French (français)"), 306 PAIR(Language, French, tr("French (français)")),
290 PAIR(Language, German, "German (Deutsch)"), 307 PAIR(Language, German, tr("German (Deutsch)")),
291 PAIR(Language, Italian, "Italian (italiano)"), 308 PAIR(Language, Italian, tr("Italian (italiano)")),
292 PAIR(Language, Spanish, "Spanish (español)"), 309 PAIR(Language, Spanish, tr("Spanish (español)")),
293 PAIR(Language, Chinese, "Chinese"), 310 PAIR(Language, Chinese, tr("Chinese")),
294 PAIR(Language, Korean, "Korean (한국어)"), 311 PAIR(Language, Korean, tr("Korean (한국어)")),
295 PAIR(Language, Dutch, "Dutch (Nederlands)"), 312 PAIR(Language, Dutch, tr("Dutch (Nederlands)")),
296 PAIR(Language, Portuguese, "Portuguese (português)"), 313 PAIR(Language, Portuguese, tr("Portuguese (português)")),
297 PAIR(Language, Russian, "Russian (Русский)"), 314 PAIR(Language, Russian, tr("Russian (Русский)")),
298 PAIR(Language, Taiwanese, "Taiwanese"), 315 PAIR(Language, Taiwanese, tr("Taiwanese")),
299 PAIR(Language, EnglishBritish, "British English"), 316 PAIR(Language, EnglishBritish, tr("British English")),
300 PAIR(Language, FrenchCanadian, "Canadian French"), 317 PAIR(Language, FrenchCanadian, tr("Canadian French")),
301 PAIR(Language, SpanishLatin, "Latin American Spanish"), 318 PAIR(Language, SpanishLatin, tr("Latin American Spanish")),
302 PAIR(Language, ChineseSimplified, "Simplified Chinese"), 319 PAIR(Language, ChineseSimplified, tr("Simplified Chinese")),
303 PAIR(Language, ChineseTraditional, "Traditional Chinese (正體中文)"), 320 PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")),
304 PAIR(Language, PortugueseBrazilian, "Brazilian Portuguese (português do Brasil)"), 321 PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")),
305 }}); 322 }});
306 translations->insert({Settings::EnumMetadata<Settings::Region>::Index(), 323 translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
307 { 324 {
308 PAIR(Region, Japan, "Japan"), 325 PAIR(Region, Japan, tr("Japan")),
309 PAIR(Region, Usa, "USA"), 326 PAIR(Region, Usa, tr("USA")),
310 PAIR(Region, Europe, "Europe"), 327 PAIR(Region, Europe, tr("Europe")),
311 PAIR(Region, Australia, "Australia"), 328 PAIR(Region, Australia, tr("Australia")),
312 PAIR(Region, China, "China"), 329 PAIR(Region, China, tr("China")),
313 PAIR(Region, Korea, "Korea"), 330 PAIR(Region, Korea, tr("Korea")),
314 PAIR(Region, Taiwan, "Taiwan"), 331 PAIR(Region, Taiwan, tr("Taiwan")),
315 }}); 332 }});
316 translations->insert( 333 translations->insert(
317 {Settings::EnumMetadata<Settings::TimeZone>::Index(), 334 {Settings::EnumMetadata<Settings::TimeZone>::Index(),
@@ -323,72 +340,74 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
323 {static_cast<u32>(Settings::TimeZone::Default), 340 {static_cast<u32>(Settings::TimeZone::Default),
324 tr("Default (%1)", "Default time zone") 341 tr("Default (%1)", "Default time zone")
325 .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))}, 342 .arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))},
326 PAIR(TimeZone, Cet, "CET"), 343 PAIR(TimeZone, Cet, tr("CET")),
327 PAIR(TimeZone, Cst6Cdt, "CST6CDT"), 344 PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")),
328 PAIR(TimeZone, Cuba, "Cuba"), 345 PAIR(TimeZone, Cuba, tr("Cuba")),
329 PAIR(TimeZone, Eet, "EET"), 346 PAIR(TimeZone, Eet, tr("EET")),
330 PAIR(TimeZone, Egypt, "Egypt"), 347 PAIR(TimeZone, Egypt, tr("Egypt")),
331 PAIR(TimeZone, Eire, "Eire"), 348 PAIR(TimeZone, Eire, tr("Eire")),
332 PAIR(TimeZone, Est, "EST"), 349 PAIR(TimeZone, Est, tr("EST")),
333 PAIR(TimeZone, Est5Edt, "EST5EDT"), 350 PAIR(TimeZone, Est5Edt, tr("EST5EDT")),
334 PAIR(TimeZone, Gb, "GB"), 351 PAIR(TimeZone, Gb, tr("GB")),
335 PAIR(TimeZone, GbEire, "GB-Eire"), 352 PAIR(TimeZone, GbEire, tr("GB-Eire")),
336 PAIR(TimeZone, Gmt, "GMT"), 353 PAIR(TimeZone, Gmt, tr("GMT")),
337 PAIR(TimeZone, GmtPlusZero, "GMT+0"), 354 PAIR(TimeZone, GmtPlusZero, tr("GMT+0")),
338 PAIR(TimeZone, GmtMinusZero, "GMT-0"), 355 PAIR(TimeZone, GmtMinusZero, tr("GMT-0")),
339 PAIR(TimeZone, GmtZero, "GMT0"), 356 PAIR(TimeZone, GmtZero, tr("GMT0")),
340 PAIR(TimeZone, Greenwich, "Greenwich"), 357 PAIR(TimeZone, Greenwich, tr("Greenwich")),
341 PAIR(TimeZone, Hongkong, "Hongkong"), 358 PAIR(TimeZone, Hongkong, tr("Hongkong")),
342 PAIR(TimeZone, Hst, "HST"), 359 PAIR(TimeZone, Hst, tr("HST")),
343 PAIR(TimeZone, Iceland, "Iceland"), 360 PAIR(TimeZone, Iceland, tr("Iceland")),
344 PAIR(TimeZone, Iran, "Iran"), 361 PAIR(TimeZone, Iran, tr("Iran")),
345 PAIR(TimeZone, Israel, "Israel"), 362 PAIR(TimeZone, Israel, tr("Israel")),
346 PAIR(TimeZone, Jamaica, "Jamaica"), 363 PAIR(TimeZone, Jamaica, tr("Jamaica")),
347 PAIR(TimeZone, Japan, "Japan"), 364 PAIR(TimeZone, Japan, tr("Japan")),
348 PAIR(TimeZone, Kwajalein, "Kwajalein"), 365 PAIR(TimeZone, Kwajalein, tr("Kwajalein")),
349 PAIR(TimeZone, Libya, "Libya"), 366 PAIR(TimeZone, Libya, tr("Libya")),
350 PAIR(TimeZone, Met, "MET"), 367 PAIR(TimeZone, Met, tr("MET")),
351 PAIR(TimeZone, Mst, "MST"), 368 PAIR(TimeZone, Mst, tr("MST")),
352 PAIR(TimeZone, Mst7Mdt, "MST7MDT"), 369 PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")),
353 PAIR(TimeZone, Navajo, "Navajo"), 370 PAIR(TimeZone, Navajo, tr("Navajo")),
354 PAIR(TimeZone, Nz, "NZ"), 371 PAIR(TimeZone, Nz, tr("NZ")),
355 PAIR(TimeZone, NzChat, "NZ-CHAT"), 372 PAIR(TimeZone, NzChat, tr("NZ-CHAT")),
356 PAIR(TimeZone, Poland, "Poland"), 373 PAIR(TimeZone, Poland, tr("Poland")),
357 PAIR(TimeZone, Portugal, "Portugal"), 374 PAIR(TimeZone, Portugal, tr("Portugal")),
358 PAIR(TimeZone, Prc, "PRC"), 375 PAIR(TimeZone, Prc, tr("PRC")),
359 PAIR(TimeZone, Pst8Pdt, "PST8PDT"), 376 PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")),
360 PAIR(TimeZone, Roc, "ROC"), 377 PAIR(TimeZone, Roc, tr("ROC")),
361 PAIR(TimeZone, Rok, "ROK"), 378 PAIR(TimeZone, Rok, tr("ROK")),
362 PAIR(TimeZone, Singapore, "Singapore"), 379 PAIR(TimeZone, Singapore, tr("Singapore")),
363 PAIR(TimeZone, Turkey, "Turkey"), 380 PAIR(TimeZone, Turkey, tr("Turkey")),
364 PAIR(TimeZone, Uct, "UCT"), 381 PAIR(TimeZone, Uct, tr("UCT")),
365 PAIR(TimeZone, Universal, "Universal"), 382 PAIR(TimeZone, Universal, tr("Universal")),
366 PAIR(TimeZone, Utc, "UTC"), 383 PAIR(TimeZone, Utc, tr("UTC")),
367 PAIR(TimeZone, WSu, "W-SU"), 384 PAIR(TimeZone, WSu, tr("W-SU")),
368 PAIR(TimeZone, Wet, "WET"), 385 PAIR(TimeZone, Wet, tr("WET")),
369 PAIR(TimeZone, Zulu, "Zulu"), 386 PAIR(TimeZone, Zulu, tr("Zulu")),
370 }}); 387 }});
371 translations->insert({Settings::EnumMetadata<Settings::AudioMode>::Index(), 388 translations->insert({Settings::EnumMetadata<Settings::AudioMode>::Index(),
372 { 389 {
373 PAIR(AudioMode, Mono, "Mono"), 390 PAIR(AudioMode, Mono, tr("Mono")),
374 PAIR(AudioMode, Stereo, "Stereo"), 391 PAIR(AudioMode, Stereo, tr("Stereo")),
375 PAIR(AudioMode, Surround, "Surround"), 392 PAIR(AudioMode, Surround, tr("Surround")),
376 }}); 393 }});
377 translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(), 394 translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(),
378 { 395 {
379 PAIR(MemoryLayout, Memory_4Gb, "4GB DRAM (Default)"), 396 PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")),
380 PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"), 397 PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")),
381 PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"), 398 PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM (Unsafe)")),
399 }});
400 translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
401 {
402 PAIR(ConsoleMode, Docked, tr("Docked")),
403 PAIR(ConsoleMode, Handheld, tr("Handheld")),
382 }}); 404 }});
383 translations->insert(
384 {Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
385 {PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}});
386 translations->insert( 405 translations->insert(
387 {Settings::EnumMetadata<Settings::ConfirmStop>::Index(), 406 {Settings::EnumMetadata<Settings::ConfirmStop>::Index(),
388 { 407 {
389 PAIR(ConfirmStop, Ask_Always, "Always ask (Default)"), 408 PAIR(ConfirmStop, Ask_Always, tr("Always ask (Default)")),
390 PAIR(ConfirmStop, Ask_Based_On_Game, "Only if game specifies not to stop"), 409 PAIR(ConfirmStop, Ask_Based_On_Game, tr("Only if game specifies not to stop")),
391 PAIR(ConfirmStop, Ask_Never, "Never ask"), 410 PAIR(ConfirmStop, Ask_Never, tr("Never ask")),
392 }}); 411 }});
393 412
394#undef PAIR 413#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 @@
10#include <vector> 10#include <vector>
11#include <QString> 11#include <QString>
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/settings.h"
13 14
14class QWidget; 15class QWidget;
15 16
@@ -22,4 +23,46 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent);
22 23
23std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent); 24std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent);
24 25
26static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map = {
27 {Settings::AntiAliasing::None, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "None"))},
28 {Settings::AntiAliasing::Fxaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FXAA"))},
29 {Settings::AntiAliasing::Smaa, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SMAA"))},
30};
31
32static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map = {
33 {Settings::ScalingFilter::NearestNeighbor,
34 QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Nearest"))},
35 {Settings::ScalingFilter::Bilinear,
36 QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bilinear"))},
37 {Settings::ScalingFilter::Bicubic, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Bicubic"))},
38 {Settings::ScalingFilter::Gaussian,
39 QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Gaussian"))},
40 {Settings::ScalingFilter::ScaleForce,
41 QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "ScaleForce"))},
42 {Settings::ScalingFilter::Fsr, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "FSR"))},
43};
44
45static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map = {
46 {Settings::ConsoleMode::Docked, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Docked"))},
47 {Settings::ConsoleMode::Handheld, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Handheld"))},
48};
49
50static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = {
51 {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))},
52 {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))},
53 {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))},
54};
55
56static const std::map<Settings::RendererBackend, QString> renderer_backend_texts_map = {
57 {Settings::RendererBackend::Vulkan, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Vulkan"))},
58 {Settings::RendererBackend::OpenGL, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "OpenGL"))},
59 {Settings::RendererBackend::Null, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Null"))},
60};
61
62static const std::map<Settings::ShaderBackend, QString> shader_backend_texts_map = {
63 {Settings::ShaderBackend::Glsl, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLSL"))},
64 {Settings::ShaderBackend::Glasm, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "GLASM"))},
65 {Settings::ShaderBackend::SpirV, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "SPIRV"))},
66};
67
25} // namespace ConfigurationShared 68} // 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,
194 return group; 194 return group;
195 } 195 }
196 196
197 const auto get_selected = [=]() -> int { 197 const auto get_selected = [this]() -> int {
198 for (const auto& [id, button] : radio_buttons) { 198 for (const auto& [id, button] : radio_buttons) {
199 if (button->isChecked()) { 199 if (button->isChecked()) {
200 return id; 200 return id;
@@ -203,7 +203,7 @@ QWidget* Widget::CreateRadioGroup(std::function<std::string()>& serializer,
203 return -1; 203 return -1;
204 }; 204 };
205 205
206 const auto set_index = [=](u32 value) { 206 const auto set_index = [this](u32 value) {
207 for (const auto& [id, button] : radio_buttons) { 207 for (const auto& [id, button] : radio_buttons) {
208 button->setChecked(id == value); 208 button->setChecked(id == value);
209 } 209 }
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{{
36 36
37bool IsDarkTheme() { 37bool IsDarkTheme() {
38 const auto& theme = UISettings::values.theme; 38 const auto& theme = UISettings::values.theme;
39 return theme == QStringLiteral("qdarkstyle") || 39 return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") ||
40 theme == QStringLiteral("qdarkstyle_midnight_blue") || 40 theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue");
41 theme == QStringLiteral("colorful_dark") ||
42 theme == QStringLiteral("colorful_midnight_blue");
43} 41}
44 42
45} // namespace 43} // 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() {
278 case GameListItemType::CustomDir: { 278 case GameListItemType::CustomDir: {
279 const UISettings::GameDir& game_dir = 279 const UISettings::GameDir& game_dir =
280 UISettings::values.game_dirs[child->data(GameListDir::GameDirRole).toInt()]; 280 UISettings::values.game_dirs[child->data(GameListDir::GameDirRole).toInt()];
281 const QString icon_name = QFileInfo::exists(game_dir.path) 281 const QString icon_name = QFileInfo::exists(QString::fromStdString(game_dir.path))
282 ? QStringLiteral("folder") 282 ? QStringLiteral("folder")
283 : QStringLiteral("bad_folder"); 283 : QStringLiteral("bad_folder");
284 child->setData( 284 child->setData(
@@ -727,7 +727,8 @@ void GameList::AddPermDirPopup(QMenu& context_menu, QModelIndex selected) {
727 }); 727 });
728 728
729 connect(open_directory_location, &QAction::triggered, [this, game_dir_index] { 729 connect(open_directory_location, &QAction::triggered, [this, game_dir_index] {
730 emit OpenDirectory(UISettings::values.game_dirs[game_dir_index].path); 730 emit OpenDirectory(
731 QString::fromStdString(UISettings::values.game_dirs[game_dir_index].path));
731 }); 732 });
732} 733}
733 734
@@ -869,7 +870,7 @@ const QStringList GameList::supported_file_extensions = {
869 QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; 870 QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")};
870 871
871void GameList::RefreshGameDirectory() { 872void GameList::RefreshGameDirectory() {
872 if (!UISettings::values.game_dirs.isEmpty() && current_worker != nullptr) { 873 if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) {
873 LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); 874 LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list.");
874 PopulateAsync(UISettings::values.game_dirs); 875 PopulateAsync(UISettings::values.game_dirs);
875 } 876 }
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:
286 setData(QObject::tr("System Titles"), Qt::DisplayRole); 286 setData(QObject::tr("System Titles"), Qt::DisplayRole);
287 break; 287 break;
288 case GameListItemType::CustomDir: { 288 case GameListItemType::CustomDir: {
289 const QString icon_name = QFileInfo::exists(game_dir->path) 289 const QString path = QString::fromStdString(game_dir->path);
290 ? QStringLiteral("folder") 290 const QString icon_name =
291 : QStringLiteral("bad_folder"); 291 QFileInfo::exists(path) ? QStringLiteral("folder") : QStringLiteral("bad_folder");
292 setData(QIcon::fromTheme(icon_name).pixmap(icon_size).scaled( 292 setData(QIcon::fromTheme(icon_name).pixmap(icon_size).scaled(
293 icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), 293 icon_size, icon_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation),
294 Qt::DecorationRole); 294 Qt::DecorationRole);
295 setData(game_dir->path, Qt::DisplayRole); 295 setData(path, Qt::DisplayRole);
296 break; 296 break;
297 } 297 }
298 default: 298 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() {
456 break; 456 break;
457 } 457 }
458 458
459 if (game_dir.path == QStringLiteral("SDMC")) { 459 if (game_dir.path == std::string("SDMC")) {
460 auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SdmcDir); 460 auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SdmcDir);
461 DirEntryReady(game_list_dir); 461 DirEntryReady(game_list_dir);
462 AddTitlesToGameList(game_list_dir); 462 AddTitlesToGameList(game_list_dir);
463 } else if (game_dir.path == QStringLiteral("UserNAND")) { 463 } else if (game_dir.path == std::string("UserNAND")) {
464 auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::UserNandDir); 464 auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::UserNandDir);
465 DirEntryReady(game_list_dir); 465 DirEntryReady(game_list_dir);
466 AddTitlesToGameList(game_list_dir); 466 AddTitlesToGameList(game_list_dir);
467 } else if (game_dir.path == QStringLiteral("SysNAND")) { 467 } else if (game_dir.path == std::string("SysNAND")) {
468 auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SysNandDir); 468 auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SysNandDir);
469 DirEntryReady(game_list_dir); 469 DirEntryReady(game_list_dir);
470 AddTitlesToGameList(game_list_dir); 470 AddTitlesToGameList(game_list_dir);
471 } else { 471 } else {
472 watch_list.append(game_dir.path); 472 watch_list.append(QString::fromStdString(game_dir.path));
473 auto* const game_list_dir = new GameListDir(game_dir); 473 auto* const game_list_dir = new GameListDir(game_dir);
474 DirEntryReady(game_list_dir); 474 DirEntryReady(game_list_dir);
475 ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), 475 ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path, game_dir.deep_scan,
476 game_dir.deep_scan, game_list_dir); 476 game_list_dir);
477 ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), 477 ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path, game_dir.deep_scan,
478 game_dir.deep_scan, game_list_dir); 478 game_list_dir);
479 } 479 }
480 } 480 }
481 481
482 RecordEvent([=](GameList* game_list) { game_list->DonePopulating(watch_list); }); 482 RecordEvent([this](GameList* game_list) { game_list->DonePopulating(watch_list); });
483 processing_completed.Set(); 483 processing_completed.Set();
484} 484}
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() {
19 for (const auto& hotkey : group.second) { 19 for (const auto& hotkey : group.second) {
20 UISettings::values.shortcuts.push_back( 20 UISettings::values.shortcuts.push_back(
21 {hotkey.first, group.first, 21 {hotkey.first, group.first,
22 UISettings::ContextualShortcut({hotkey.second.keyseq.toString(), 22 UISettings::ContextualShortcut({hotkey.second.keyseq.toString().toStdString(),
23 hotkey.second.controller_keyseq, 23 hotkey.second.controller_keyseq,
24 hotkey.second.context, hotkey.second.repeat})}); 24 hotkey.second.context, hotkey.second.repeat})});
25 } 25 }
@@ -31,12 +31,12 @@ void HotkeyRegistry::LoadHotkeys() {
31 // beginGroup() 31 // beginGroup()
32 for (auto shortcut : UISettings::values.shortcuts) { 32 for (auto shortcut : UISettings::values.shortcuts) {
33 Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name]; 33 Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name];
34 if (!shortcut.shortcut.keyseq.isEmpty()) { 34 if (!shortcut.shortcut.keyseq.empty()) {
35 hk.keyseq = 35 hk.keyseq = QKeySequence::fromString(QString::fromStdString(shortcut.shortcut.keyseq),
36 QKeySequence::fromString(shortcut.shortcut.keyseq, QKeySequence::NativeText); 36 QKeySequence::NativeText);
37 hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.context); 37 hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.context);
38 } 38 }
39 if (!shortcut.shortcut.controller_keyseq.isEmpty()) { 39 if (!shortcut.shortcut.controller_keyseq.empty()) {
40 hk.controller_keyseq = shortcut.shortcut.controller_keyseq; 40 hk.controller_keyseq = shortcut.shortcut.controller_keyseq;
41 } 41 }
42 if (hk.shortcut) { 42 if (hk.shortcut) {
@@ -51,7 +51,8 @@ void HotkeyRegistry::LoadHotkeys() {
51 } 51 }
52} 52}
53 53
54QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { 54QShortcut* HotkeyRegistry::GetHotkey(const std::string& group, const std::string& action,
55 QWidget* widget) {
55 Hotkey& hk = hotkey_groups[group][action]; 56 Hotkey& hk = hotkey_groups[group][action];
56 57
57 if (!hk.shortcut) { 58 if (!hk.shortcut) {
@@ -62,7 +63,8 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action
62 return hk.shortcut; 63 return hk.shortcut;
63} 64}
64 65
65ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const QString& group, const QString& action, 66ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const std::string& group,
67 const std::string& action,
66 Core::HID::EmulatedController* controller) { 68 Core::HID::EmulatedController* controller) {
67 Hotkey& hk = hotkey_groups[group][action]; 69 Hotkey& hk = hotkey_groups[group][action];
68 70
@@ -74,12 +76,12 @@ ControllerShortcut* HotkeyRegistry::GetControllerHotkey(const QString& group, co
74 return hk.controller_shortcut; 76 return hk.controller_shortcut;
75} 77}
76 78
77QKeySequence HotkeyRegistry::GetKeySequence(const QString& group, const QString& action) { 79QKeySequence HotkeyRegistry::GetKeySequence(const std::string& group, const std::string& action) {
78 return hotkey_groups[group][action].keyseq; 80 return hotkey_groups[group][action].keyseq;
79} 81}
80 82
81Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const QString& group, 83Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const std::string& group,
82 const QString& action) { 84 const std::string& action) {
83 return hotkey_groups[group][action].context; 85 return hotkey_groups[group][action].context;
84} 86}
85 87
@@ -101,10 +103,10 @@ void ControllerShortcut::SetKey(const ControllerButtonSequence& buttons) {
101 button_sequence = buttons; 103 button_sequence = buttons;
102} 104}
103 105
104void ControllerShortcut::SetKey(const QString& buttons_shortcut) { 106void ControllerShortcut::SetKey(const std::string& buttons_shortcut) {
105 ControllerButtonSequence sequence{}; 107 ControllerButtonSequence sequence{};
106 name = buttons_shortcut.toStdString(); 108 name = buttons_shortcut;
107 std::istringstream command_line(buttons_shortcut.toStdString()); 109 std::istringstream command_line(buttons_shortcut);
108 std::string line; 110 std::string line;
109 while (std::getline(command_line, line, '+')) { 111 while (std::getline(command_line, line, '+')) {
110 if (line.empty()) { 112 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:
33 ~ControllerShortcut(); 33 ~ControllerShortcut();
34 34
35 void SetKey(const ControllerButtonSequence& buttons); 35 void SetKey(const ControllerButtonSequence& buttons);
36 void SetKey(const QString& buttons_shortcut); 36 void SetKey(const std::string& buttons_shortcut);
37 37
38 ControllerButtonSequence ButtonSequence() const; 38 ControllerButtonSequence ButtonSequence() const;
39 39
@@ -88,8 +88,8 @@ public:
88 * will be the same. Thus, you shouldn't rely on the caller really being the 88 * will be the same. Thus, you shouldn't rely on the caller really being the
89 * QShortcut's parent. 89 * QShortcut's parent.
90 */ 90 */
91 QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); 91 QShortcut* GetHotkey(const std::string& group, const std::string& action, QWidget* widget);
92 ControllerShortcut* GetControllerHotkey(const QString& group, const QString& action, 92 ControllerShortcut* GetControllerHotkey(const std::string& group, const std::string& action,
93 Core::HID::EmulatedController* controller); 93 Core::HID::EmulatedController* controller);
94 94
95 /** 95 /**
@@ -98,7 +98,7 @@ public:
98 * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger"). 98 * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger").
99 * @param action Name of the action (e.g. "Start Emulation", "Load Image"). 99 * @param action Name of the action (e.g. "Start Emulation", "Load Image").
100 */ 100 */
101 QKeySequence GetKeySequence(const QString& group, const QString& action); 101 QKeySequence GetKeySequence(const std::string& group, const std::string& action);
102 102
103 /** 103 /**
104 * Returns a Qt::ShortcutContext object who can be connected to other 104 * Returns a Qt::ShortcutContext object who can be connected to other
@@ -108,20 +108,20 @@ public:
108 * "Debugger"). 108 * "Debugger").
109 * @param action Name of the action (e.g. "Start Emulation", "Load Image"). 109 * @param action Name of the action (e.g. "Start Emulation", "Load Image").
110 */ 110 */
111 Qt::ShortcutContext GetShortcutContext(const QString& group, const QString& action); 111 Qt::ShortcutContext GetShortcutContext(const std::string& group, const std::string& action);
112 112
113private: 113private:
114 struct Hotkey { 114 struct Hotkey {
115 QKeySequence keyseq; 115 QKeySequence keyseq;
116 QString controller_keyseq; 116 std::string controller_keyseq;
117 QShortcut* shortcut = nullptr; 117 QShortcut* shortcut = nullptr;
118 ControllerShortcut* controller_shortcut = nullptr; 118 ControllerShortcut* controller_shortcut = nullptr;
119 Qt::ShortcutContext context = Qt::WindowShortcut; 119 Qt::ShortcutContext context = Qt::WindowShortcut;
120 bool repeat; 120 bool repeat;
121 }; 121 };
122 122
123 using HotkeyMap = std::map<QString, Hotkey>; 123 using HotkeyMap = std::map<std::string, Hotkey>;
124 using HotkeyGroupMap = std::map<QString, HotkeyMap>; 124 using HotkeyGroupMap = std::map<std::string, HotkeyMap>;
125 125
126 HotkeyGroupMap hotkey_groups; 126 HotkeyGroupMap hotkey_groups;
127}; 127};
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
128#include "core/loader/loader.h" 128#include "core/loader/loader.h"
129#include "core/perf_stats.h" 129#include "core/perf_stats.h"
130#include "core/telemetry_session.h" 130#include "core/telemetry_session.h"
131#include "frontend_common/config.h"
131#include "input_common/drivers/tas_input.h" 132#include "input_common/drivers/tas_input.h"
132#include "input_common/drivers/virtual_amiibo.h" 133#include "input_common/drivers/virtual_amiibo.h"
133#include "input_common/main.h" 134#include "input_common/main.h"
@@ -140,9 +141,9 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
140#include "yuzu/bootmanager.h" 141#include "yuzu/bootmanager.h"
141#include "yuzu/compatdb.h" 142#include "yuzu/compatdb.h"
142#include "yuzu/compatibility_list.h" 143#include "yuzu/compatibility_list.h"
143#include "yuzu/configuration/config.h"
144#include "yuzu/configuration/configure_dialog.h" 144#include "yuzu/configuration/configure_dialog.h"
145#include "yuzu/configuration/configure_input_per_game.h" 145#include "yuzu/configuration/configure_input_per_game.h"
146#include "yuzu/configuration/qt_config.h"
146#include "yuzu/debugger/console.h" 147#include "yuzu/debugger/console.h"
147#include "yuzu/debugger/controller.h" 148#include "yuzu/debugger/controller.h"
148#include "yuzu/debugger/profiler.h" 149#include "yuzu/debugger/profiler.h"
@@ -311,7 +312,7 @@ bool GMainWindow::CheckDarkMode() {
311#endif // __unix__ 312#endif // __unix__
312} 313}
313 314
314GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan) 315GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan)
315 : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, 316 : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
316 input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)}, 317 input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)},
317 vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, 318 vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
@@ -676,7 +677,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
676 // Don't forget to apply settings. 677 // Don't forget to apply settings.
677 system->HIDCore().DisableAllControllerConfiguration(); 678 system->HIDCore().DisableAllControllerConfiguration();
678 system->ApplySettings(); 679 system->ApplySettings();
679 config->Save(); 680 config->SaveAllValues();
680 681
681 UpdateStatusButtons(); 682 UpdateStatusButtons();
682 683
@@ -1129,7 +1130,7 @@ void GMainWindow::InitializeWidgets() {
1129 connect(aa_status_button, &QPushButton::customContextMenuRequested, 1130 connect(aa_status_button, &QPushButton::customContextMenuRequested,
1130 [this](const QPoint& menu_location) { 1131 [this](const QPoint& menu_location) {
1131 QMenu context_menu; 1132 QMenu context_menu;
1132 for (auto const& aa_text_pair : Config::anti_aliasing_texts_map) { 1133 for (auto const& aa_text_pair : ConfigurationShared::anti_aliasing_texts_map) {
1133 context_menu.addAction(aa_text_pair.second, [this, aa_text_pair] { 1134 context_menu.addAction(aa_text_pair.second, [this, aa_text_pair] {
1134 Settings::values.anti_aliasing.SetValue(aa_text_pair.first); 1135 Settings::values.anti_aliasing.SetValue(aa_text_pair.first);
1135 UpdateAAText(); 1136 UpdateAAText();
@@ -1153,7 +1154,7 @@ void GMainWindow::InitializeWidgets() {
1153 connect(filter_status_button, &QPushButton::customContextMenuRequested, 1154 connect(filter_status_button, &QPushButton::customContextMenuRequested,
1154 [this](const QPoint& menu_location) { 1155 [this](const QPoint& menu_location) {
1155 QMenu context_menu; 1156 QMenu context_menu;
1156 for (auto const& filter_text_pair : Config::scaling_filter_texts_map) { 1157 for (auto const& filter_text_pair : ConfigurationShared::scaling_filter_texts_map) {
1157 context_menu.addAction(filter_text_pair.second, [this, filter_text_pair] { 1158 context_menu.addAction(filter_text_pair.second, [this, filter_text_pair] {
1158 Settings::values.scaling_filter.SetValue(filter_text_pair.first); 1159 Settings::values.scaling_filter.SetValue(filter_text_pair.first);
1159 UpdateFilterText(); 1160 UpdateFilterText();
@@ -1176,7 +1177,7 @@ void GMainWindow::InitializeWidgets() {
1176 [this](const QPoint& menu_location) { 1177 [this](const QPoint& menu_location) {
1177 QMenu context_menu; 1178 QMenu context_menu;
1178 1179
1179 for (auto const& pair : Config::use_docked_mode_texts_map) { 1180 for (auto const& pair : ConfigurationShared::use_docked_mode_texts_map) {
1180 context_menu.addAction(pair.second, [this, &pair] { 1181 context_menu.addAction(pair.second, [this, &pair] {
1181 if (pair.first != Settings::values.use_docked_mode.GetValue()) { 1182 if (pair.first != Settings::values.use_docked_mode.GetValue()) {
1182 OnToggleDockedMode(); 1183 OnToggleDockedMode();
@@ -1200,7 +1201,7 @@ void GMainWindow::InitializeWidgets() {
1200 [this](const QPoint& menu_location) { 1201 [this](const QPoint& menu_location) {
1201 QMenu context_menu; 1202 QMenu context_menu;
1202 1203
1203 for (auto const& gpu_accuracy_pair : Config::gpu_accuracy_texts_map) { 1204 for (auto const& gpu_accuracy_pair : ConfigurationShared::gpu_accuracy_texts_map) {
1204 if (gpu_accuracy_pair.first == Settings::GpuAccuracy::Extreme) { 1205 if (gpu_accuracy_pair.first == Settings::GpuAccuracy::Extreme) {
1205 continue; 1206 continue;
1206 } 1207 }
@@ -1229,7 +1230,8 @@ void GMainWindow::InitializeWidgets() {
1229 [this](const QPoint& menu_location) { 1230 [this](const QPoint& menu_location) {
1230 QMenu context_menu; 1231 QMenu context_menu;
1231 1232
1232 for (auto const& renderer_backend_pair : Config::renderer_backend_texts_map) { 1233 for (auto const& renderer_backend_pair :
1234 ConfigurationShared::renderer_backend_texts_map) {
1233 if (renderer_backend_pair.first == Settings::RendererBackend::Null) { 1235 if (renderer_backend_pair.first == Settings::RendererBackend::Null) {
1234 continue; 1236 continue;
1235 } 1237 }
@@ -1294,16 +1296,17 @@ void GMainWindow::InitializeRecentFileMenuActions() {
1294 1296
1295void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name, 1297void GMainWindow::LinkActionShortcut(QAction* action, const QString& action_name,
1296 const bool tas_allowed) { 1298 const bool tas_allowed) {
1297 static const QString main_window = QStringLiteral("Main Window"); 1299 static const auto main_window = std::string("Main Window");
1298 action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name)); 1300 action->setShortcut(hotkey_registry.GetKeySequence(main_window, action_name.toStdString()));
1299 action->setShortcutContext(hotkey_registry.GetShortcutContext(main_window, action_name)); 1301 action->setShortcutContext(
1302 hotkey_registry.GetShortcutContext(main_window, action_name.toStdString()));
1300 action->setAutoRepeat(false); 1303 action->setAutoRepeat(false);
1301 1304
1302 this->addAction(action); 1305 this->addAction(action);
1303 1306
1304 auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); 1307 auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
1305 const auto* controller_hotkey = 1308 const auto* controller_hotkey =
1306 hotkey_registry.GetControllerHotkey(main_window, action_name, controller); 1309 hotkey_registry.GetControllerHotkey(main_window, action_name.toStdString(), controller);
1307 connect( 1310 connect(
1308 controller_hotkey, &ControllerShortcut::Activated, this, 1311 controller_hotkey, &ControllerShortcut::Activated, this,
1309 [action, tas_allowed, this] { 1312 [action, tas_allowed, this] {
@@ -1335,10 +1338,11 @@ void GMainWindow::InitializeHotkeys() {
1335 1338
1336 static const QString main_window = QStringLiteral("Main Window"); 1339 static const QString main_window = QStringLiteral("Main Window");
1337 const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) { 1340 const auto connect_shortcut = [&]<typename Fn>(const QString& action_name, const Fn& function) {
1338 const auto* hotkey = hotkey_registry.GetHotkey(main_window, action_name, this); 1341 const auto* hotkey =
1342 hotkey_registry.GetHotkey(main_window.toStdString(), action_name.toStdString(), this);
1339 auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); 1343 auto* controller = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
1340 const auto* controller_hotkey = 1344 const auto* controller_hotkey = hotkey_registry.GetControllerHotkey(
1341 hotkey_registry.GetControllerHotkey(main_window, action_name, controller); 1345 main_window.toStdString(), action_name.toStdString(), controller);
1342 connect(hotkey, &QShortcut::activated, this, function); 1346 connect(hotkey, &QShortcut::activated, this, function);
1343 connect(controller_hotkey, &ControllerShortcut::Activated, this, function, 1347 connect(controller_hotkey, &ControllerShortcut::Activated, this, function,
1344 Qt::QueuedConnection); 1348 Qt::QueuedConnection);
@@ -1918,7 +1922,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1918 // Save configurations 1922 // Save configurations
1919 UpdateUISettings(); 1923 UpdateUISettings();
1920 game_list->SaveInterfaceLayout(); 1924 game_list->SaveInterfaceLayout();
1921 config->Save(); 1925 config->SaveAllValues();
1922 1926
1923 u64 title_id{0}; 1927 u64 title_id{0};
1924 1928
@@ -1936,7 +1940,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1936 const auto config_file_name = title_id == 0 1940 const auto config_file_name = title_id == 0
1937 ? Common::FS::PathToUTF8String(file_path.filename()) 1941 ? Common::FS::PathToUTF8String(file_path.filename())
1938 : fmt::format("{:016X}", title_id); 1942 : fmt::format("{:016X}", title_id);
1939 Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); 1943 QtConfig per_game_config(config_file_name, Config::ConfigType::PerGameConfig);
1940 system->HIDCore().ReloadInputDevices(); 1944 system->HIDCore().ReloadInputDevices();
1941 system->ApplySettings(); 1945 system->ApplySettings();
1942 } 1946 }
@@ -3135,7 +3139,7 @@ void GMainWindow::OnGameListAddDirectory() {
3135 return; 3139 return;
3136 } 3140 }
3137 3141
3138 UISettings::GameDir game_dir{dir_path, false, true}; 3142 UISettings::GameDir game_dir{dir_path.toStdString(), false, true};
3139 if (!UISettings::values.game_dirs.contains(game_dir)) { 3143 if (!UISettings::values.game_dirs.contains(game_dir)) {
3140 UISettings::values.game_dirs.append(game_dir); 3144 UISettings::values.game_dirs.append(game_dir);
3141 game_list->PopulateAsync(UISettings::values.game_dirs); 3145 game_list->PopulateAsync(UISettings::values.game_dirs);
@@ -3181,14 +3185,14 @@ void GMainWindow::OnMenuLoadFile() {
3181 "%1 is an identifier for the Switch executable file extensions.") 3185 "%1 is an identifier for the Switch executable file extensions.")
3182 .arg(extensions); 3186 .arg(extensions);
3183 const QString filename = QFileDialog::getOpenFileName( 3187 const QString filename = QFileDialog::getOpenFileName(
3184 this, tr("Load File"), UISettings::values.roms_path, file_filter); 3188 this, tr("Load File"), QString::fromStdString(UISettings::values.roms_path), file_filter);
3185 is_load_file_select_active = false; 3189 is_load_file_select_active = false;
3186 3190
3187 if (filename.isEmpty()) { 3191 if (filename.isEmpty()) {
3188 return; 3192 return;
3189 } 3193 }
3190 3194
3191 UISettings::values.roms_path = QFileInfo(filename).path(); 3195 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
3192 BootGame(filename); 3196 BootGame(filename);
3193} 3197}
3194 3198
@@ -3221,7 +3225,8 @@ void GMainWindow::OnMenuInstallToNAND() {
3221 "Image (*.xci)"); 3225 "Image (*.xci)");
3222 3226
3223 QStringList filenames = QFileDialog::getOpenFileNames( 3227 QStringList filenames = QFileDialog::getOpenFileNames(
3224 this, tr("Install Files"), UISettings::values.roms_path, file_filter); 3228 this, tr("Install Files"), QString::fromStdString(UISettings::values.roms_path),
3229 file_filter);
3225 3230
3226 if (filenames.isEmpty()) { 3231 if (filenames.isEmpty()) {
3227 return; 3232 return;
@@ -3239,7 +3244,7 @@ void GMainWindow::OnMenuInstallToNAND() {
3239 } 3244 }
3240 3245
3241 // Save folder location of the first selected file 3246 // Save folder location of the first selected file
3242 UISettings::values.roms_path = QFileInfo(filenames[0]).path(); 3247 UISettings::values.roms_path = QFileInfo(filenames[0]).path().toStdString();
3243 3248
3244 int remaining = filenames.size(); 3249 int remaining = filenames.size();
3245 3250
@@ -3584,7 +3589,7 @@ void GMainWindow::OnExit() {
3584 3589
3585void GMainWindow::OnSaveConfig() { 3590void GMainWindow::OnSaveConfig() {
3586 system->ApplySettings(); 3591 system->ApplySettings();
3587 config->Save(); 3592 config->SaveAllValues();
3588} 3593}
3589 3594
3590void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { 3595void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
@@ -3840,7 +3845,7 @@ void GMainWindow::OnConfigure() {
3840 3845
3841 Settings::values.disabled_addons.clear(); 3846 Settings::values.disabled_addons.clear();
3842 3847
3843 config = std::make_unique<Config>(); 3848 config = std::make_unique<QtConfig>();
3844 UISettings::values.reset_to_defaults = false; 3849 UISettings::values.reset_to_defaults = false;
3845 3850
3846 UISettings::values.game_dirs = std::move(old_game_dirs); 3851 UISettings::values.game_dirs = std::move(old_game_dirs);
@@ -3875,7 +3880,7 @@ void GMainWindow::OnConfigure() {
3875 3880
3876 UISettings::values.configuration_applied = false; 3881 UISettings::values.configuration_applied = false;
3877 3882
3878 config->Save(); 3883 config->SaveAllValues();
3879 3884
3880 if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) { 3885 if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) {
3881 render_window->installEventFilter(render_window); 3886 render_window->installEventFilter(render_window);
@@ -4091,7 +4096,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
4091 UISettings::values.configuration_applied = false; 4096 UISettings::values.configuration_applied = false;
4092 4097
4093 if (!is_powered_on) { 4098 if (!is_powered_on) {
4094 config->Save(); 4099 config->SaveAllValues();
4095 } 4100 }
4096} 4101}
4097 4102
@@ -4324,7 +4329,7 @@ void GMainWindow::OnAlbum() {
4324 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer); 4329 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer);
4325 4330
4326 const auto filename = QString::fromStdString(album_nca->GetFullPath()); 4331 const auto filename = QString::fromStdString(album_nca->GetFullPath());
4327 UISettings::values.roms_path = QFileInfo(filename).path(); 4332 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4328 BootGame(filename, AlbumId); 4333 BootGame(filename, AlbumId);
4329} 4334}
4330 4335
@@ -4348,7 +4353,7 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
4348 system->GetAppletManager().SetCabinetMode(mode); 4353 system->GetAppletManager().SetCabinetMode(mode);
4349 4354
4350 const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); 4355 const auto filename = QString::fromStdString(cabinet_nca->GetFullPath());
4351 UISettings::values.roms_path = QFileInfo(filename).path(); 4356 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4352 BootGame(filename, CabinetId); 4357 BootGame(filename, CabinetId);
4353} 4358}
4354 4359
@@ -4371,7 +4376,7 @@ void GMainWindow::OnMiiEdit() {
4371 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); 4376 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit);
4372 4377
4373 const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); 4378 const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath()));
4374 UISettings::values.roms_path = QFileInfo(filename).path(); 4379 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4375 BootGame(filename, MiiEditId); 4380 BootGame(filename, MiiEditId);
4376} 4381}
4377 4382
@@ -4396,7 +4401,7 @@ void GMainWindow::OnOpenControllerMenu() {
4396 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller); 4401 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller);
4397 4402
4398 const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); 4403 const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath()));
4399 UISettings::values.roms_path = QFileInfo(filename).path(); 4404 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4400 BootGame(filename, ControllerAppletId); 4405 BootGame(filename, ControllerAppletId);
4401} 4406}
4402 4407
@@ -4590,7 +4595,8 @@ void GMainWindow::UpdateStatusBar() {
4590 4595
4591void GMainWindow::UpdateGPUAccuracyButton() { 4596void GMainWindow::UpdateGPUAccuracyButton() {
4592 const auto gpu_accuracy = Settings::values.gpu_accuracy.GetValue(); 4597 const auto gpu_accuracy = Settings::values.gpu_accuracy.GetValue();
4593 const auto gpu_accuracy_text = Config::gpu_accuracy_texts_map.find(gpu_accuracy)->second; 4598 const auto gpu_accuracy_text =
4599 ConfigurationShared::gpu_accuracy_texts_map.find(gpu_accuracy)->second;
4594 gpu_accuracy_button->setText(gpu_accuracy_text.toUpper()); 4600 gpu_accuracy_button->setText(gpu_accuracy_text.toUpper());
4595 gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GpuAccuracy::Normal); 4601 gpu_accuracy_button->setChecked(gpu_accuracy != Settings::GpuAccuracy::Normal);
4596} 4602}
@@ -4599,31 +4605,32 @@ void GMainWindow::UpdateDockedButton() {
4599 const auto console_mode = Settings::values.use_docked_mode.GetValue(); 4605 const auto console_mode = Settings::values.use_docked_mode.GetValue();
4600 dock_status_button->setChecked(Settings::IsDockedMode()); 4606 dock_status_button->setChecked(Settings::IsDockedMode());
4601 dock_status_button->setText( 4607 dock_status_button->setText(
4602 Config::use_docked_mode_texts_map.find(console_mode)->second.toUpper()); 4608 ConfigurationShared::use_docked_mode_texts_map.find(console_mode)->second.toUpper());
4603} 4609}
4604 4610
4605void GMainWindow::UpdateAPIText() { 4611void GMainWindow::UpdateAPIText() {
4606 const auto api = Settings::values.renderer_backend.GetValue(); 4612 const auto api = Settings::values.renderer_backend.GetValue();
4607 const auto renderer_status_text = Config::renderer_backend_texts_map.find(api)->second; 4613 const auto renderer_status_text =
4614 ConfigurationShared::renderer_backend_texts_map.find(api)->second;
4608 renderer_status_button->setText( 4615 renderer_status_button->setText(
4609 api == Settings::RendererBackend::OpenGL 4616 api == Settings::RendererBackend::OpenGL
4610 ? tr("%1 %2").arg( 4617 ? tr("%1 %2").arg(renderer_status_text.toUpper(),
4611 renderer_status_text.toUpper(), 4618 ConfigurationShared::shader_backend_texts_map
4612 Config::shader_backend_texts_map.find(Settings::values.shader_backend.GetValue()) 4619 .find(Settings::values.shader_backend.GetValue())
4613 ->second) 4620 ->second)
4614 : renderer_status_text.toUpper()); 4621 : renderer_status_text.toUpper());
4615} 4622}
4616 4623
4617void GMainWindow::UpdateFilterText() { 4624void GMainWindow::UpdateFilterText() {
4618 const auto filter = Settings::values.scaling_filter.GetValue(); 4625 const auto filter = Settings::values.scaling_filter.GetValue();
4619 const auto filter_text = Config::scaling_filter_texts_map.find(filter)->second; 4626 const auto filter_text = ConfigurationShared::scaling_filter_texts_map.find(filter)->second;
4620 filter_status_button->setText(filter == Settings::ScalingFilter::Fsr ? tr("FSR") 4627 filter_status_button->setText(filter == Settings::ScalingFilter::Fsr ? tr("FSR")
4621 : filter_text.toUpper()); 4628 : filter_text.toUpper());
4622} 4629}
4623 4630
4624void GMainWindow::UpdateAAText() { 4631void GMainWindow::UpdateAAText() {
4625 const auto aa_mode = Settings::values.anti_aliasing.GetValue(); 4632 const auto aa_mode = Settings::values.anti_aliasing.GetValue();
4626 const auto aa_text = Config::anti_aliasing_texts_map.find(aa_mode)->second; 4633 const auto aa_text = ConfigurationShared::anti_aliasing_texts_map.find(aa_mode)->second;
4627 aa_status_button->setText(aa_mode == Settings::AntiAliasing::None 4634 aa_status_button->setText(aa_mode == Settings::AntiAliasing::None
4628 ? QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "NO AA")) 4635 ? QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "NO AA"))
4629 : aa_text.toUpper()); 4636 : aa_text.toUpper());
@@ -4926,6 +4933,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
4926 4933
4927 UpdateUISettings(); 4934 UpdateUISettings();
4928 game_list->SaveInterfaceLayout(); 4935 game_list->SaveInterfaceLayout();
4936 UISettings::SaveWindowState();
4929 hotkey_registry.SaveHotkeys(); 4937 hotkey_registry.SaveHotkeys();
4930 4938
4931 // Unload controllers early 4939 // Unload controllers early
@@ -5080,9 +5088,9 @@ static void AdjustLinkColor() {
5080} 5088}
5081 5089
5082void GMainWindow::UpdateUITheme() { 5090void GMainWindow::UpdateUITheme() {
5083 const QString default_theme = 5091 const QString default_theme = QString::fromUtf8(
5084 QString::fromUtf8(UISettings::themes[static_cast<size_t>(Config::default_theme)].second); 5092 UISettings::themes[static_cast<size_t>(UISettings::default_theme)].second);
5085 QString current_theme = UISettings::values.theme; 5093 QString current_theme = QString::fromStdString(UISettings::values.theme);
5086 5094
5087 if (current_theme.isEmpty()) { 5095 if (current_theme.isEmpty()) {
5088 current_theme = default_theme; 5096 current_theme = default_theme;
@@ -5110,7 +5118,7 @@ void GMainWindow::UpdateUITheme() {
5110 QFile f(theme_uri); 5118 QFile f(theme_uri);
5111 if (!f.open(QFile::ReadOnly | QFile::Text)) { 5119 if (!f.open(QFile::ReadOnly | QFile::Text)) {
5112 LOG_ERROR(Frontend, "Unable to open style \"{}\", fallback to the default theme", 5120 LOG_ERROR(Frontend, "Unable to open style \"{}\", fallback to the default theme",
5113 UISettings::values.theme.toStdString()); 5121 UISettings::values.theme);
5114 current_theme = default_theme; 5122 current_theme = default_theme;
5115 } 5123 }
5116 } 5124 }
@@ -5123,7 +5131,7 @@ void GMainWindow::UpdateUITheme() {
5123 setStyleSheet(ts.readAll()); 5131 setStyleSheet(ts.readAll());
5124 } else { 5132 } else {
5125 LOG_ERROR(Frontend, "Unable to set style \"{}\", stylesheet file not found", 5133 LOG_ERROR(Frontend, "Unable to set style \"{}\", stylesheet file not found",
5126 UISettings::values.theme.toStdString()); 5134 UISettings::values.theme);
5127 qApp->setStyleSheet({}); 5135 qApp->setStyleSheet({});
5128 setStyleSheet({}); 5136 setStyleSheet({});
5129 } 5137 }
@@ -5132,27 +5140,28 @@ void GMainWindow::UpdateUITheme() {
5132void GMainWindow::LoadTranslation() { 5140void GMainWindow::LoadTranslation() {
5133 bool loaded; 5141 bool loaded;
5134 5142
5135 if (UISettings::values.language.isEmpty()) { 5143 if (UISettings::values.language.empty()) {
5136 // If the selected language is empty, use system locale 5144 // If the selected language is empty, use system locale
5137 loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/")); 5145 loaded = translator.load(QLocale(), {}, {}, QStringLiteral(":/languages/"));
5138 } else { 5146 } else {
5139 // Otherwise load from the specified file 5147 // Otherwise load from the specified file
5140 loaded = translator.load(UISettings::values.language, QStringLiteral(":/languages/")); 5148 loaded = translator.load(QString::fromStdString(UISettings::values.language),
5149 QStringLiteral(":/languages/"));
5141 } 5150 }
5142 5151
5143 if (loaded) { 5152 if (loaded) {
5144 qApp->installTranslator(&translator); 5153 qApp->installTranslator(&translator);
5145 } else { 5154 } else {
5146 UISettings::values.language = QStringLiteral("en"); 5155 UISettings::values.language = std::string("en");
5147 } 5156 }
5148} 5157}
5149 5158
5150void GMainWindow::OnLanguageChanged(const QString& locale) { 5159void GMainWindow::OnLanguageChanged(const QString& locale) {
5151 if (UISettings::values.language != QStringLiteral("en")) { 5160 if (UISettings::values.language != std::string("en")) {
5152 qApp->removeTranslator(&translator); 5161 qApp->removeTranslator(&translator);
5153 } 5162 }
5154 5163
5155 UISettings::values.language = locale; 5164 UISettings::values.language = locale.toStdString();
5156 LoadTranslation(); 5165 LoadTranslation();
5157 ui->retranslateUi(this); 5166 ui->retranslateUi(this);
5158 multiplayer_state->retranslateUi(); 5167 multiplayer_state->retranslateUi();
@@ -5178,7 +5187,7 @@ void GMainWindow::changeEvent(QEvent* event) {
5178 // UpdateUITheme is a decent work around 5187 // UpdateUITheme is a decent work around
5179 if (event->type() == QEvent::PaletteChange) { 5188 if (event->type() == QEvent::PaletteChange) {
5180 const QPalette test_palette(qApp->palette()); 5189 const QPalette test_palette(qApp->palette());
5181 const QString current_theme = UISettings::values.theme; 5190 const QString current_theme = QString::fromStdString(UISettings::values.theme);
5182 // Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too 5191 // Keeping eye on QPalette::Window to avoid looping. QPalette::Text might be useful too
5183 static QColor last_window_color; 5192 static QColor last_window_color;
5184 const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window); 5193 const QColor window_color = test_palette.color(QPalette::Active, QPalette::Window);
@@ -5272,7 +5281,8 @@ static void SetHighDPIAttributes() {
5272} 5281}
5273 5282
5274int main(int argc, char* argv[]) { 5283int main(int argc, char* argv[]) {
5275 std::unique_ptr<Config> config = std::make_unique<Config>(); 5284 std::unique_ptr<QtConfig> config = std::make_unique<QtConfig>();
5285 UISettings::RestoreWindowState(config);
5276 bool has_broken_vulkan = false; 5286 bool has_broken_vulkan = false;
5277 bool is_child = false; 5287 bool is_child = false;
5278 if (CheckEnvVars(&is_child)) { 5288 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 @@
15 15
16#include "common/announce_multiplayer_room.h" 16#include "common/announce_multiplayer_room.h"
17#include "common/common_types.h" 17#include "common/common_types.h"
18#include "configuration/qt_config.h"
18#include "input_common/drivers/tas_input.h" 19#include "input_common/drivers/tas_input.h"
19#include "yuzu/compatibility_list.h" 20#include "yuzu/compatibility_list.h"
20#include "yuzu/hotkeys.h" 21#include "yuzu/hotkeys.h"
@@ -26,7 +27,7 @@
26#include <QtDBus/QtDBus> 27#include <QtDBus/QtDBus>
27#endif 28#endif
28 29
29class Config; 30class QtConfig;
30class ClickableLabel; 31class ClickableLabel;
31class EmuThread; 32class EmuThread;
32class GameList; 33class GameList;
@@ -185,7 +186,7 @@ class GMainWindow : public QMainWindow {
185public: 186public:
186 void filterBarSetChecked(bool state); 187 void filterBarSetChecked(bool state);
187 void UpdateUITheme(); 188 void UpdateUITheme();
188 explicit GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan); 189 explicit GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulkan);
189 ~GMainWindow() override; 190 ~GMainWindow() override;
190 191
191 bool DropAction(QDropEvent* event); 192 bool DropAction(QDropEvent* event);
@@ -521,7 +522,7 @@ private:
521 QSlider* volume_slider = nullptr; 522 QSlider* volume_slider = nullptr;
522 QTimer status_bar_update_timer; 523 QTimer status_bar_update_timer;
523 524
524 std::unique_ptr<Config> config; 525 std::unique_ptr<QtConfig> config;
525 526
526 // Whether emulation is currently running in yuzu. 527 // Whether emulation is currently running in yuzu.
527 bool emulation_running = false; 528 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 @@
1// SPDX-FileCopyrightText: 2016 Citra Emulator Project 1// SPDX-FileCopyrightText: 2016 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <QSettings>
5#include "common/fs/fs.h"
6#include "common/fs/path_util.h"
4#include "yuzu/uisettings.h" 7#include "yuzu/uisettings.h"
5 8
6#ifndef CANNOT_EXPLICITLY_INSTANTIATE 9#ifndef CANNOT_EXPLICITLY_INSTANTIATE
@@ -15,6 +18,8 @@ template class Setting<unsigned long long>;
15} // namespace Settings 18} // namespace Settings
16#endif 19#endif
17 20
21namespace FS = Common::FS;
22
18namespace UISettings { 23namespace UISettings {
19 24
20const Themes themes{{ 25const Themes themes{{
@@ -28,10 +33,8 @@ const Themes themes{{
28 33
29bool IsDarkTheme() { 34bool IsDarkTheme() {
30 const auto& theme = UISettings::values.theme; 35 const auto& theme = UISettings::values.theme;
31 return theme == QStringLiteral("qdarkstyle") || 36 return theme == std::string("qdarkstyle") || theme == std::string("qdarkstyle_midnight_blue") ||
32 theme == QStringLiteral("qdarkstyle_midnight_blue") || 37 theme == std::string("colorful_dark") || theme == std::string("colorful_midnight_blue");
33 theme == QStringLiteral("colorful_dark") ||
34 theme == QStringLiteral("colorful_midnight_blue");
35} 38}
36 39
37Values values = {}; 40Values values = {};
@@ -52,4 +55,58 @@ u32 CalculateWidth(u32 height, Settings::AspectRatio ratio) {
52 return height * 16 / 9; 55 return height * 16 / 9;
53} 56}
54 57
58void SaveWindowState() {
59 const auto window_state_config_loc =
60 FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "window_state.ini");
61
62 void(FS::CreateParentDir(window_state_config_loc));
63 QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
64
65 config.setValue(QStringLiteral("geometry"), values.geometry);
66 config.setValue(QStringLiteral("state"), values.state);
67 config.setValue(QStringLiteral("geometryRenderWindow"), values.renderwindow_geometry);
68 config.setValue(QStringLiteral("gameListHeaderState"), values.gamelist_header_state);
69 config.setValue(QStringLiteral("microProfileDialogGeometry"), values.microprofile_geometry);
70
71 config.sync();
72}
73
74void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig) {
75 const auto window_state_config_loc =
76 FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "window_state.ini");
77
78 // Migrate window state from old location
79 if (!FS::Exists(window_state_config_loc) && qtConfig->Exists("UI", "UILayout\\geometry")) {
80 const auto config_loc =
81 FS::PathToUTF8String(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "qt-config.ini");
82 QSettings config(QString::fromStdString(config_loc), QSettings::IniFormat);
83
84 config.beginGroup(QStringLiteral("UI"));
85 config.beginGroup(QStringLiteral("UILayout"));
86 values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
87 values.state = config.value(QStringLiteral("state")).toByteArray();
88 values.renderwindow_geometry =
89 config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
90 values.gamelist_header_state =
91 config.value(QStringLiteral("gameListHeaderState")).toByteArray();
92 values.microprofile_geometry =
93 config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
94 config.endGroup();
95 config.endGroup();
96 return;
97 }
98
99 void(FS::CreateParentDir(window_state_config_loc));
100 const QSettings config(QString::fromStdString(window_state_config_loc), QSettings::IniFormat);
101
102 values.geometry = config.value(QStringLiteral("geometry")).toByteArray();
103 values.state = config.value(QStringLiteral("state")).toByteArray();
104 values.renderwindow_geometry =
105 config.value(QStringLiteral("geometryRenderWindow")).toByteArray();
106 values.gamelist_header_state =
107 config.value(QStringLiteral("gameListHeaderState")).toByteArray();
108 values.microprofile_geometry =
109 config.value(QStringLiteral("microProfileDialogGeometry")).toByteArray();
110}
111
55} // namespace UISettings 112} // 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 @@
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/settings.h" 15#include "common/settings.h"
16#include "common/settings_enums.h" 16#include "common/settings_enums.h"
17#include "configuration/qt_config.h"
17 18
18using Settings::Category; 19using Settings::Category;
19using Settings::ConfirmStop; 20using Settings::ConfirmStop;
@@ -37,15 +38,15 @@ namespace UISettings {
37bool IsDarkTheme(); 38bool IsDarkTheme();
38 39
39struct ContextualShortcut { 40struct ContextualShortcut {
40 QString keyseq; 41 std::string keyseq;
41 QString controller_keyseq; 42 std::string controller_keyseq;
42 int context; 43 int context;
43 bool repeat; 44 bool repeat;
44}; 45};
45 46
46struct Shortcut { 47struct Shortcut {
47 QString name; 48 std::string name;
48 QString group; 49 std::string group;
49 ContextualShortcut shortcut; 50 ContextualShortcut shortcut;
50}; 51};
51 52
@@ -58,11 +59,19 @@ enum class Theme {
58 MidnightBlueColorful, 59 MidnightBlueColorful,
59}; 60};
60 61
62static constexpr Theme default_theme{
63#ifdef _WIN32
64 Theme::DarkColorful
65#else
66 Theme::DefaultColorful
67#endif
68};
69
61using Themes = std::array<std::pair<const char*, const char*>, 6>; 70using Themes = std::array<std::pair<const char*, const char*>, 6>;
62extern const Themes themes; 71extern const Themes themes;
63 72
64struct GameDir { 73struct GameDir {
65 QString path; 74 std::string path;
66 bool deep_scan = false; 75 bool deep_scan = false;
67 bool expanded = false; 76 bool expanded = false;
68 bool operator==(const GameDir& rhs) const { 77 bool operator==(const GameDir& rhs) const {
@@ -144,15 +153,15 @@ struct Values {
144 Category::Screenshots}; 153 Category::Screenshots};
145 Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots}; 154 Setting<u32> screenshot_height{linkage, 0, "screenshot_height", Category::Screenshots};
146 155
147 QString roms_path; 156 std::string roms_path;
148 QString symbols_path; 157 std::string symbols_path;
149 QString game_dir_deprecated; 158 std::string game_dir_deprecated;
150 bool game_dir_deprecated_deepscan; 159 bool game_dir_deprecated_deepscan;
151 QVector<UISettings::GameDir> game_dirs; 160 QVector<GameDir> game_dirs;
152 QStringList recent_files; 161 QStringList recent_files;
153 QString language; 162 std::string language;
154 163
155 QString theme; 164 std::string theme;
156 165
157 // Shortcut name <Shortcut, context> 166 // Shortcut name <Shortcut, context>
158 std::vector<Shortcut> shortcuts; 167 std::vector<Shortcut> shortcuts;
@@ -206,6 +215,54 @@ extern Values values;
206 215
207u32 CalculateWidth(u32 height, Settings::AspectRatio ratio); 216u32 CalculateWidth(u32 height, Settings::AspectRatio ratio);
208 217
218void SaveWindowState();
219void RestoreWindowState(std::unique_ptr<QtConfig>& qtConfig);
220
221// This shouldn't have anything except static initializers (no functions). So
222// QKeySequence(...).toString() is NOT ALLOWED HERE.
223// This must be in alphabetical order according to action name as it must have the same order as
224// UISetting::values.shortcuts, which is alphabetically ordered.
225// clang-format off
226const std::array<Shortcut, 23> default_hotkeys{{
227 {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}},
228 {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}},
229 {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}},
230 {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}},
231 {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}},
232 {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}},
233 {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}},
234 {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}},
235 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string("Esc"), std::string(""), Qt::WindowShortcut, false}},
236 {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}},
237 {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}},
238 {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}},
239 {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}},
240 {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}},
241 {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}},
242 {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}},
243 {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}},
244 {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}},
245 {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}},
246 {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}},
247 {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}},
248 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")).toStdString(), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")).toStdString(), {std::string(""), std::string(""), Qt::ApplicationShortcut, false}},
249 {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}},
250}};
251// clang-format on
252
209} // namespace UISettings 253} // namespace UISettings
210 254
211Q_DECLARE_METATYPE(UISettings::GameDir*); 255Q_DECLARE_METATYPE(UISettings::GameDir*);
256
257// These metatype declarations cannot be in common/settings.h because core is devoid of QT
258Q_DECLARE_METATYPE(Settings::CpuAccuracy);
259Q_DECLARE_METATYPE(Settings::GpuAccuracy);
260Q_DECLARE_METATYPE(Settings::FullscreenMode);
261Q_DECLARE_METATYPE(Settings::NvdecEmulation);
262Q_DECLARE_METATYPE(Settings::ResolutionSetup);
263Q_DECLARE_METATYPE(Settings::ScalingFilter);
264Q_DECLARE_METATYPE(Settings::AntiAliasing);
265Q_DECLARE_METATYPE(Settings::RendererBackend);
266Q_DECLARE_METATYPE(Settings::ShaderBackend);
267Q_DECLARE_METATYPE(Settings::AstcRecompression);
268Q_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)
13endfunction() 13endfunction()
14 14
15add_executable(yuzu-cmd 15add_executable(yuzu-cmd
16 config.cpp
17 config.h
18 default_ini.h
19 emu_window/emu_window_sdl2.cpp 16 emu_window/emu_window_sdl2.cpp
20 emu_window/emu_window_sdl2.h 17 emu_window/emu_window_sdl2.h
21 emu_window/emu_window_sdl2_gl.cpp 18 emu_window/emu_window_sdl2_gl.cpp
@@ -25,14 +22,16 @@ add_executable(yuzu-cmd
25 emu_window/emu_window_sdl2_vk.cpp 22 emu_window/emu_window_sdl2_vk.cpp
26 emu_window/emu_window_sdl2_vk.h 23 emu_window/emu_window_sdl2_vk.h
27 precompiled_headers.h 24 precompiled_headers.h
25 sdl_config.cpp
26 sdl_config.h
28 yuzu.cpp 27 yuzu.cpp
29 yuzu.rc 28 yuzu.rc
30) 29)
31 30
32create_target_directory_groups(yuzu-cmd) 31create_target_directory_groups(yuzu-cmd)
33 32
34target_link_libraries(yuzu-cmd PRIVATE common core input_common) 33target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common)
35target_link_libraries(yuzu-cmd PRIVATE inih::INIReader glad) 34target_link_libraries(yuzu-cmd PRIVATE glad)
36if (MSVC) 35if (MSVC)
37 target_link_libraries(yuzu-cmd PRIVATE getopt) 36 target_link_libraries(yuzu-cmd PRIVATE getopt)
38endif() 37endif()
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 @@
1// SPDX-FileCopyrightText: 2014 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <memory>
5#include <optional>
6#include <sstream>
7#include <INIReader.h>
8#include <SDL.h>
9#include "common/fs/file.h"
10#include "common/fs/fs.h"
11#include "common/fs/path_util.h"
12#include "common/logging/log.h"
13#include "common/settings.h"
14#include "core/hle/service/acc/profile_manager.h"
15#include "input_common/main.h"
16#include "yuzu_cmd/config.h"
17#include "yuzu_cmd/default_ini.h"
18
19namespace FS = Common::FS;
20
21const std::filesystem::path default_config_path =
22 FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "sdl2-config.ini";
23
24Config::Config(std::optional<std::filesystem::path> config_path)
25 : sdl2_config_loc{config_path.value_or(default_config_path)},
26 sdl2_config{std::make_unique<INIReader>(FS::PathToUTF8String(sdl2_config_loc))} {
27 Reload();
28}
29
30Config::~Config() = default;
31
32bool Config::LoadINI(const std::string& default_contents, bool retry) {
33 const auto config_loc_str = FS::PathToUTF8String(sdl2_config_loc);
34 if (sdl2_config->ParseError() < 0) {
35 if (retry) {
36 LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...",
37 config_loc_str);
38
39 void(FS::CreateParentDir(sdl2_config_loc));
40 void(FS::WriteStringToFile(sdl2_config_loc, FS::FileType::TextFile, default_contents));
41
42 sdl2_config = std::make_unique<INIReader>(config_loc_str);
43
44 return LoadINI(default_contents, false);
45 }
46 LOG_ERROR(Config, "Failed.");
47 return false;
48 }
49 LOG_INFO(Config, "Successfully loaded {}", config_loc_str);
50 return true;
51}
52
53static const std::array<int, Settings::NativeButton::NumButtons> default_buttons = {
54 SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T,
55 SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W,
56 SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B,
57};
58
59static const std::array<int, Settings::NativeMotion::NumMotions> default_motions = {
60 SDL_SCANCODE_7,
61 SDL_SCANCODE_8,
62};
63
64static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs{{
65 {
66 SDL_SCANCODE_UP,
67 SDL_SCANCODE_DOWN,
68 SDL_SCANCODE_LEFT,
69 SDL_SCANCODE_RIGHT,
70 SDL_SCANCODE_D,
71 },
72 {
73 SDL_SCANCODE_I,
74 SDL_SCANCODE_K,
75 SDL_SCANCODE_J,
76 SDL_SCANCODE_L,
77 SDL_SCANCODE_D,
78 },
79}};
80
81template <>
82void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) {
83 std::string setting_value = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
84 if (setting_value.empty()) {
85 setting_value = setting.GetDefault();
86 }
87 setting = std::move(setting_value);
88}
89
90template <>
91void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) {
92 setting = sdl2_config->GetBoolean(group, setting.GetLabel(), setting.GetDefault());
93}
94
95template <typename Type, bool ranged>
96void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) {
97 setting = static_cast<Type>(sdl2_config->GetInteger(group, setting.GetLabel(),
98 static_cast<long>(setting.GetDefault())));
99}
100
101void Config::ReadCategory(Settings::Category category) {
102 for (const auto setting : Settings::values.linkage.by_category[category]) {
103 const char* category_name = [&]() {
104 if (category == Settings::Category::Controls) {
105 // For compatibility with older configs
106 return "ControlsGeneral";
107 } else {
108 return Settings::TranslateCategory(category);
109 }
110 }();
111 std::string setting_value =
112 sdl2_config->Get(category_name, setting->GetLabel(), setting->DefaultToString());
113 setting->LoadString(setting_value);
114 }
115}
116
117void Config::ReadValues() {
118 // Controls
119 ReadCategory(Settings::Category::Controls);
120
121 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
122 auto& player = Settings::values.players.GetValue()[p];
123
124 const auto group = fmt::format("ControlsP{}", p);
125 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
126 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
127 player.buttons[i] =
128 sdl2_config->Get(group, Settings::NativeButton::mapping[i], default_param);
129 if (player.buttons[i].empty()) {
130 player.buttons[i] = default_param;
131 }
132 }
133
134 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
135 std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
136 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
137 default_analogs[i][3], default_analogs[i][4], 0.5f);
138 player.analogs[i] =
139 sdl2_config->Get(group, Settings::NativeAnalog::mapping[i], default_param);
140 if (player.analogs[i].empty()) {
141 player.analogs[i] = default_param;
142 }
143 }
144
145 for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
146 const std::string default_param =
147 InputCommon::GenerateKeyboardParam(default_motions[i]);
148 auto& player_motions = player.motions[i];
149
150 player_motions =
151 sdl2_config->Get(group, Settings::NativeMotion::mapping[i], default_param);
152 if (player_motions.empty()) {
153 player_motions = default_param;
154 }
155 }
156
157 player.connected = sdl2_config->GetBoolean(group, "connected", false);
158 }
159
160 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
161 std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
162 Settings::values.debug_pad_buttons[i] = sdl2_config->Get(
163 "ControlsGeneral", std::string("debug_pad_") + Settings::NativeButton::mapping[i],
164 default_param);
165 if (Settings::values.debug_pad_buttons[i].empty())
166 Settings::values.debug_pad_buttons[i] = default_param;
167 }
168
169 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
170 std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
171 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
172 default_analogs[i][3], default_analogs[i][4], 0.5f);
173 Settings::values.debug_pad_analogs[i] = sdl2_config->Get(
174 "ControlsGeneral", std::string("debug_pad_") + Settings::NativeAnalog::mapping[i],
175 default_param);
176 if (Settings::values.debug_pad_analogs[i].empty())
177 Settings::values.debug_pad_analogs[i] = default_param;
178 }
179
180 Settings::values.touchscreen.enabled =
181 sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
182 Settings::values.touchscreen.rotation_angle =
183 sdl2_config->GetInteger("ControlsGeneral", "touch_angle", 0);
184 Settings::values.touchscreen.diameter_x =
185 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_x", 15);
186 Settings::values.touchscreen.diameter_y =
187 sdl2_config->GetInteger("ControlsGeneral", "touch_diameter_y", 15);
188
189 int num_touch_from_button_maps =
190 sdl2_config->GetInteger("ControlsGeneral", "touch_from_button_map", 0);
191 if (num_touch_from_button_maps > 0) {
192 for (int i = 0; i < num_touch_from_button_maps; ++i) {
193 Settings::TouchFromButtonMap map;
194 map.name = sdl2_config->Get("ControlsGeneral",
195 std::string("touch_from_button_maps_") + std::to_string(i) +
196 std::string("_name"),
197 "default");
198 const int num_touch_maps = sdl2_config->GetInteger(
199 "ControlsGeneral",
200 std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"),
201 0);
202 map.buttons.reserve(num_touch_maps);
203
204 for (int j = 0; j < num_touch_maps; ++j) {
205 std::string touch_mapping =
206 sdl2_config->Get("ControlsGeneral",
207 std::string("touch_from_button_maps_") + std::to_string(i) +
208 std::string("_bind_") + std::to_string(j),
209 "");
210 map.buttons.emplace_back(std::move(touch_mapping));
211 }
212
213 Settings::values.touch_from_button_maps.emplace_back(std::move(map));
214 }
215 } else {
216 Settings::values.touch_from_button_maps.emplace_back(
217 Settings::TouchFromButtonMap{"default", {}});
218 num_touch_from_button_maps = 1;
219 }
220 Settings::values.touch_from_button_map_index = std::clamp(
221 Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
222
223 ReadCategory(Settings::Category::Audio);
224 ReadCategory(Settings::Category::Core);
225 ReadCategory(Settings::Category::Cpu);
226 ReadCategory(Settings::Category::CpuDebug);
227 ReadCategory(Settings::Category::CpuUnsafe);
228 ReadCategory(Settings::Category::Renderer);
229 ReadCategory(Settings::Category::RendererAdvanced);
230 ReadCategory(Settings::Category::RendererDebug);
231 ReadCategory(Settings::Category::System);
232 ReadCategory(Settings::Category::SystemAudio);
233 ReadCategory(Settings::Category::DataStorage);
234 ReadCategory(Settings::Category::Debugging);
235 ReadCategory(Settings::Category::DebuggingGraphics);
236 ReadCategory(Settings::Category::Miscellaneous);
237 ReadCategory(Settings::Category::Network);
238 ReadCategory(Settings::Category::WebService);
239
240 // Data Storage
241 FS::SetYuzuPath(FS::YuzuPath::NANDDir,
242 sdl2_config->Get("Data Storage", "nand_directory",
243 FS::GetYuzuPathString(FS::YuzuPath::NANDDir)));
244 FS::SetYuzuPath(FS::YuzuPath::SDMCDir,
245 sdl2_config->Get("Data Storage", "sdmc_directory",
246 FS::GetYuzuPathString(FS::YuzuPath::SDMCDir)));
247 FS::SetYuzuPath(FS::YuzuPath::LoadDir,
248 sdl2_config->Get("Data Storage", "load_directory",
249 FS::GetYuzuPathString(FS::YuzuPath::LoadDir)));
250 FS::SetYuzuPath(FS::YuzuPath::DumpDir,
251 sdl2_config->Get("Data Storage", "dump_directory",
252 FS::GetYuzuPathString(FS::YuzuPath::DumpDir)));
253
254 // Debugging
255 Settings::values.record_frame_times =
256 sdl2_config->GetBoolean("Debugging", "record_frame_times", false);
257
258 const auto title_list = sdl2_config->Get("AddOns", "title_ids", "");
259 std::stringstream ss(title_list);
260 std::string line;
261 while (std::getline(ss, line, '|')) {
262 const auto title_id = std::strtoul(line.c_str(), nullptr, 16);
263 const auto disabled_list = sdl2_config->Get("AddOns", "disabled_" + line, "");
264
265 std::stringstream inner_ss(disabled_list);
266 std::string inner_line;
267 std::vector<std::string> out;
268 while (std::getline(inner_ss, inner_line, '|')) {
269 out.push_back(inner_line);
270 }
271
272 Settings::values.disabled_addons.insert_or_assign(title_id, out);
273 }
274}
275
276void Config::Reload() {
277 LoadINI(DefaultINI::sdl2_config_file);
278 ReadValues();
279}
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 @@
1// SPDX-FileCopyrightText: 2014 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <filesystem>
7#include <memory>
8#include <optional>
9#include <string>
10
11#include "common/settings.h"
12
13class INIReader;
14
15class Config {
16 std::filesystem::path sdl2_config_loc;
17 std::unique_ptr<INIReader> sdl2_config;
18
19 bool LoadINI(const std::string& default_contents = "", bool retry = true);
20 void ReadValues();
21
22public:
23 explicit Config(std::optional<std::filesystem::path> config_path);
24 ~Config();
25
26 void Reload();
27
28private:
29 /**
30 * Applies a value read from the sdl2_config to a Setting.
31 *
32 * @param group The name of the INI group
33 * @param setting The yuzu setting to modify
34 */
35 template <typename Type, bool ranged>
36 void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting);
37 void ReadCategory(Settings::Category category);
38};
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 @@
1// SPDX-FileCopyrightText: 2014 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6namespace DefaultINI {
7
8const char* sdl2_config_file =
9 R"(
10[ControlsP0]
11# The input devices and parameters for each Switch native input
12# The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ...
13# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..."
14# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values
15
16# Indicates if this player should be connected at boot
17# 0 (default): Disabled, 1: Enabled
18connected=
19
20# for button input, the following devices are available:
21# - "keyboard" (default) for keyboard input. Required parameters:
22# - "code": the code of the key to bind
23# - "sdl" for joystick input using SDL. Required parameters:
24# - "guid": SDL identification GUID of the joystick
25# - "port": the index of the joystick to bind
26# - "button"(optional): the index of the button to bind
27# - "hat"(optional): the index of the hat to bind as direction buttons
28# - "axis"(optional): the index of the axis to bind
29# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right"
30# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is
31# triggered if the axis value crosses
32# - "direction"(only used for axis): "+" means the button is triggered when the axis value
33# is greater than the threshold; "-" means the button is triggered when the axis value
34# is smaller than the threshold
35button_a=
36button_b=
37button_x=
38button_y=
39button_lstick=
40button_rstick=
41button_l=
42button_r=
43button_zl=
44button_zr=
45button_plus=
46button_minus=
47button_dleft=
48button_dup=
49button_dright=
50button_ddown=
51button_lstick_left=
52button_lstick_up=
53button_lstick_right=
54button_lstick_down=
55button_sl=
56button_sr=
57button_home=
58button_screenshot=
59
60# for analog input, the following devices are available:
61# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters:
62# - "up", "down", "left", "right": sub-devices for each direction.
63# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00"
64# - "modifier": sub-devices as a modifier.
65# - "modifier_scale": a float number representing the applied modifier scale to the analog input.
66# Must be in range of 0.0-1.0. Defaults to 0.5
67# - "sdl" for joystick input using SDL. Required parameters:
68# - "guid": SDL identification GUID of the joystick
69# - "port": the index of the joystick to bind
70# - "axis_x": the index of the axis to bind as x-axis (default to 0)
71# - "axis_y": the index of the axis to bind as y-axis (default to 1)
72lstick=
73rstick=
74
75# for motion input, the following devices are available:
76# - "keyboard" (default) for emulating random motion input from buttons. Required parameters:
77# - "code": the code of the key to bind
78# - "sdl" for motion input using SDL. Required parameters:
79# - "guid": SDL identification GUID of the joystick
80# - "port": the index of the joystick to bind
81# - "motion": the index of the motion sensor to bind
82# - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters:
83# - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001"
84# - "port": the port of the cemu hook server
85# - "pad": the index of the joystick
86# - "motion": the index of the motion sensor of the joystick to bind
87motionleft=
88motionright=
89
90[ControlsGeneral]
91# To use the debug_pad, prepend `debug_pad_` before each button setting above.
92# i.e. debug_pad_button_a=
93
94# Enable debug pad inputs to the guest
95# 0 (default): Disabled, 1: Enabled
96debug_pad_enabled =
97
98# Enable sdl raw input. Allows to configure up to 8 xinput controllers.
99# 0 (default): Disabled, 1: Enabled
100enable_raw_input =
101
102# Enable yuzu joycon driver instead of SDL drive.
103# 0: Disabled, 1 (default): Enabled
104enable_joycon_driver =
105
106# Emulates an analog input from buttons. Allowing to dial any angle.
107# 0 (default): Disabled, 1: Enabled
108emulate_analog_keyboard =
109
110# Whether to enable or disable vibration
111# 0: Disabled, 1 (default): Enabled
112vibration_enabled=
113
114# Whether to enable or disable accurate vibrations
115# 0 (default): Disabled, 1: Enabled
116enable_accurate_vibrations=
117
118# Enables controller motion inputs
119# 0: Disabled, 1 (default): Enabled
120motion_enabled =
121
122# Defines the udp device's touch screen coordinate system for cemuhookudp devices
123# - "min_x", "min_y", "max_x", "max_y"
124touch_device=
125
126# for mapping buttons to touch inputs.
127#touch_from_button_map=1
128#touch_from_button_maps_0_name=default
129#touch_from_button_maps_0_count=2
130#touch_from_button_maps_0_bind_0=foo
131#touch_from_button_maps_0_bind_1=bar
132# etc.
133
134# List of Cemuhook UDP servers, delimited by ','.
135# Default: 127.0.0.1:26760
136# Example: 127.0.0.1:26760,123.4.5.67:26761
137udp_input_servers =
138
139# Enable controlling an axis via a mouse input.
140# 0 (default): Off, 1: On
141mouse_panning =
142
143# Set mouse panning horizontal sensitivity.
144# Default: 50.0
145mouse_panning_x_sensitivity =
146
147# Set mouse panning vertical sensitivity.
148# Default: 50.0
149mouse_panning_y_sensitivity =
150
151# Set mouse panning deadzone horizontal counterweight.
152# Default: 0.0
153mouse_panning_deadzone_x_counterweight =
154
155# Set mouse panning deadzone vertical counterweight.
156# Default: 0.0
157mouse_panning_deadzone_y_counterweight =
158
159# Set mouse panning stick decay strength.
160# Default: 22.0
161mouse_panning_decay_strength =
162
163# Set mouse panning stick minimum decay.
164# Default: 5.0
165mouse_panning_minimum_decay =
166
167# Emulate an analog control stick from keyboard inputs.
168# 0 (default): Disabled, 1: Enabled
169emulate_analog_keyboard =
170
171# Enable mouse inputs to the guest
172# 0 (default): Disabled, 1: Enabled
173mouse_enabled =
174
175# Enable keyboard inputs to the guest
176# 0 (default): Disabled, 1: Enabled
177keyboard_enabled =
178
179)"
180 R"(
181[Core]
182# Whether to use multi-core for CPU emulation
183# 0: Disabled, 1 (default): Enabled
184use_multi_core =
185
186# Enable unsafe extended guest system memory layout (8GB DRAM)
187# 0 (default): Disabled, 1: Enabled
188use_unsafe_extended_memory_layout =
189
190[Cpu]
191# Adjusts various optimizations.
192# Auto-select mode enables choice unsafe optimizations.
193# Accurate enables only safe optimizations.
194# Unsafe allows any unsafe optimizations.
195# 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations
196cpu_accuracy =
197
198# Allow disabling safe optimizations.
199# 0 (default): Disabled, 1: Enabled
200cpu_debug_mode =
201
202# Enable inline page tables optimization (faster guest memory access)
203# 0: Disabled, 1 (default): Enabled
204cpuopt_page_tables =
205
206# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps)
207# 0: Disabled, 1 (default): Enabled
208cpuopt_block_linking =
209
210# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns)
211# 0: Disabled, 1 (default): Enabled
212cpuopt_return_stack_buffer =
213
214# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture)
215# 0: Disabled, 1 (default): Enabled
216cpuopt_fast_dispatcher =
217
218# Enable context elimination CPU Optimization (reduce host memory use for guest context)
219# 0: Disabled, 1 (default): Enabled
220cpuopt_context_elimination =
221
222# Enable constant propagation CPU optimization (basic IR optimization)
223# 0: Disabled, 1 (default): Enabled
224cpuopt_const_prop =
225
226# Enable miscellaneous CPU optimizations (basic IR optimization)
227# 0: Disabled, 1 (default): Enabled
228cpuopt_misc_ir =
229
230# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access)
231# 0: Disabled, 1 (default): Enabled
232cpuopt_reduce_misalign_checks =
233
234# Enable Host MMU Emulation (faster guest memory access)
235# 0: Disabled, 1 (default): Enabled
236cpuopt_fastmem =
237
238# Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access)
239# 0: Disabled, 1 (default): Enabled
240cpuopt_fastmem_exclusives =
241
242# Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access)
243# 0: Disabled, 1 (default): Enabled
244cpuopt_recompile_exclusives =
245
246# Enable optimization to ignore invalid memory accesses (faster guest memory access)
247# 0: Disabled, 1 (default): Enabled
248cpuopt_ignore_memory_aborts =
249
250# Enable unfuse FMA (improve performance on CPUs without FMA)
251# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
252# 0: Disabled, 1 (default): Enabled
253cpuopt_unsafe_unfuse_fma =
254
255# Enable faster FRSQRTE and FRECPE
256# Only enabled if cpu_accuracy is set to Unsafe.
257# 0: Disabled, 1 (default): Enabled
258cpuopt_unsafe_reduce_fp_error =
259
260# Enable faster ASIMD instructions (32 bits only)
261# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
262# 0: Disabled, 1 (default): Enabled
263cpuopt_unsafe_ignore_standard_fpcr =
264
265# Enable inaccurate NaN handling
266# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
267# 0: Disabled, 1 (default): Enabled
268cpuopt_unsafe_inaccurate_nan =
269
270# Disable address space checks (64 bits only)
271# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
272# 0: Disabled, 1 (default): Enabled
273cpuopt_unsafe_fastmem_check =
274
275# Enable faster exclusive instructions
276# Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select.
277# 0: Disabled, 1 (default): Enabled
278cpuopt_unsafe_ignore_global_monitor =
279
280)"
281 R"(
282[Renderer]
283# Which backend API to use.
284# 0: OpenGL, 1 (default): Vulkan
285backend =
286
287# Whether to enable asynchronous presentation (Vulkan only)
288# 0 (default): Off, 1: On
289async_presentation =
290
291# Enable graphics API debugging mode.
292# 0 (default): Disabled, 1: Enabled
293debug =
294
295# Enable shader feedback.
296# 0 (default): Disabled, 1: Enabled
297renderer_shader_feedback =
298
299# Enable Nsight Aftermath crash dumps
300# 0 (default): Disabled, 1: Enabled
301nsight_aftermath =
302
303# Disable shader loop safety checks, executing the shader without loop logic changes
304# 0 (default): Disabled, 1: Enabled
305disable_shader_loop_safety_checks =
306
307# Which Vulkan physical device to use (defaults to 0)
308vulkan_device =
309
310# 0: 0.5x (360p/540p) [EXPERIMENTAL]
311# 1: 0.75x (540p/810p) [EXPERIMENTAL]
312# 2 (default): 1x (720p/1080p)
313# 3: 1.5x (1080p/1620p) [EXPERIMENTAL]
314# 4: 2x (1440p/2160p)
315# 5: 3x (2160p/3240p)
316# 6: 4x (2880p/4320p)
317# 7: 5x (3600p/5400p)
318# 8: 6x (4320p/6480p)
319# 9: 7x (5040p/7560p)
320# 10: 8x (5760/8640p)
321resolution_setup =
322
323# Pixel filter to use when up- or down-sampling rendered frames.
324# 0: Nearest Neighbor
325# 1 (default): Bilinear
326# 2: Bicubic
327# 3: Gaussian
328# 4: ScaleForce
329# 5: AMD FidelityFX™️ Super Resolution
330scaling_filter =
331
332# Anti-Aliasing (AA)
333# 0 (default): None, 1: FXAA, 2: SMAA
334anti_aliasing =
335
336# Whether to use fullscreen or borderless window mode
337# 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen
338fullscreen_mode =
339
340# Aspect ratio
341# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Force 16:10, 4: Stretch to Window
342aspect_ratio =
343
344# Anisotropic filtering
345# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x
346max_anisotropy =
347
348# Whether to enable VSync or not.
349# OpenGL: Values other than 0 enable VSync
350# Vulkan: FIFO is selected if the requested mode is not supported by the driver.
351# FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate.
352# FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down.
353# Mailbox can have lower latency than FIFO and does not tear but may drop frames.
354# Immediate (no synchronization) just presents whatever is available and can exhibit tearing.
355# 0: Immediate (Off), 1: Mailbox, 2 (Default): FIFO (On), 3: FIFO Relaxed
356use_vsync =
357
358# Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is
359# not available and GLASM is selected, GLSL will be used.
360# 0: GLSL, 1 (default): GLASM, 2: SPIR-V
361shader_backend =
362
363# Uses reactive flushing instead of predictive flushing. Allowing a more accurate syncing of memory.
364# 0: Off, 1 (default): On
365use_reactive_flushing =
366
367# Whether to allow asynchronous shader building.
368# 0 (default): Off, 1: On
369use_asynchronous_shaders =
370
371# NVDEC emulation.
372# 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding
373nvdec_emulation =
374
375# Accelerate ASTC texture decoding.
376# 0: Off, 1 (default): On
377accelerate_astc =
378
379# Decode ASTC textures asynchronously.
380# 0 (default): Off, 1: On
381async_astc =
382
383# Recompress ASTC textures to a different format.
384# 0 (default): Uncompressed, 1: BC1 (Low quality), 2: BC3: (Medium quality)
385async_astc =
386
387# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value
388# 0: Off, 1: On (default)
389use_speed_limit =
390
391# Limits the speed of the game to run no faster than this value as a percentage of target speed
392# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default)
393speed_limit =
394
395# Whether to use disk based shader cache
396# 0: Off, 1 (default): On
397use_disk_shader_cache =
398
399# Which gpu accuracy level to use
400# 0: Normal, 1 (default): High, 2: Extreme (Very slow)
401gpu_accuracy =
402
403# Whether to use asynchronous GPU emulation
404# 0 : Off (slow), 1 (default): On (fast)
405use_asynchronous_gpu_emulation =
406
407# Inform the guest that GPU operations completed more quickly than they did.
408# 0: Off, 1 (default): On
409use_fast_gpu_time =
410
411# Whether to use garbage collection or not for GPU caches.
412# 0 (default): Off, 1: On
413use_caches_gc =
414
415# The clear color for the renderer. What shows up on the sides of the bottom screen.
416# Must be in range of 0-255. Defaults to 0 for all.
417bg_red =
418bg_blue =
419bg_green =
420
421)"
422 R"(
423[Audio]
424# Which audio output engine to use.
425# auto (default): Auto-select
426# cubeb: Cubeb audio engine (if available)
427# sdl2: SDL2 audio engine (if available)
428# null: No audio output
429output_engine =
430
431# Which audio device to use.
432# auto (default): Auto-select
433output_device =
434
435# Output volume.
436# 100 (default): 100%, 0; mute
437volume =
438
439[Data Storage]
440# Whether to create a virtual SD card.
441# 1 (default): Yes, 0: No
442use_virtual_sd =
443
444# Whether or not to enable gamecard emulation
445# 1: Yes, 0 (default): No
446gamecard_inserted =
447
448# Whether or not the gamecard should be emulated as the current game
449# If 'gamecard_inserted' is 0 this setting is irrelevant
450# 1: Yes, 0 (default): No
451gamecard_current_game =
452
453# Path to an XCI file to use as the gamecard
454# If 'gamecard_inserted' is 0 this setting is irrelevant
455# If 'gamecard_current_game' is 1 this setting is irrelevant
456gamecard_path =
457
458[System]
459# Whether the system is docked
460# 1 (default): Yes, 0: No
461use_docked_mode =
462
463# Sets the seed for the RNG generator built into the switch
464# rng_seed will be ignored and randomly generated if rng_seed_enabled is false
465rng_seed_enabled =
466rng_seed =
467
468# Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service
469# This will auto-increment, with the time set being the time the game is started
470# This override will only occur if custom_rtc_enabled is true, otherwise the current time is used
471custom_rtc_enabled =
472custom_rtc =
473
474# Sets the systems language index
475# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese,
476# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French,
477# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese
478language_index =
479
480# The system region that yuzu will use during emulation
481# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
482region_index =
483
484# The system time zone that yuzu will use during emulation
485# 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone
486time_zone_index =
487
488# Sets the sound output mode.
489# 0: Mono, 1 (default): Stereo, 2: Surround
490sound_index =
491
492[Miscellaneous]
493# A filter which removes logs below a certain logging level.
494# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical
495log_filter = *:Trace
496
497# Use developer keys
498# 0 (default): Disabled, 1: Enabled
499use_dev_keys =
500
501[Debugging]
502# Record frame time data, can be found in the log directory. Boolean value
503record_frame_times =
504# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
505dump_exefs=false
506# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them
507dump_nso=false
508# Determines whether or not yuzu will save the filesystem access log.
509enable_fs_access_log=false
510# Enables verbose reporting services
511reporting_services =
512# Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode
513# false: Retail/Normal Mode (default), true: Kiosk Mode
514quest_flag =
515# Determines whether debug asserts should be enabled, which will throw an exception on asserts.
516# false: Disabled (default), true: Enabled
517use_debug_asserts =
518# Determines whether unimplemented HLE service calls should be automatically stubbed.
519# false: Disabled (default), true: Enabled
520use_auto_stub =
521# Enables/Disables the macro JIT compiler
522disable_macro_jit=false
523# Determines whether to enable the GDB stub and wait for the debugger to attach before running.
524# false: Disabled (default), true: Enabled
525use_gdbstub=false
526# The port to use for the GDB server, if it is enabled.
527gdbstub_port=6543
528
529[WebService]
530# Whether or not to enable telemetry
531# 0: No, 1 (default): Yes
532enable_telemetry =
533# URL for Web API
534web_api_url = https://api.yuzu-emu.org
535# Username and token for yuzu Web Service
536# See https://profile.yuzu-emu.org/ for more info
537yuzu_username =
538yuzu_token =
539
540[Network]
541# Name of the network interface device to use with yuzu LAN play.
542# e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo'
543# e.g. On Windows: 'Ethernet', 'Wi-Fi'
544network_interface =
545
546[AddOns]
547# Used to disable add-ons
548# List of title IDs of games that will have add-ons disabled (separated by '|'):
549title_ids =
550# 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 '|')
551# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey
552)";
553} // 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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4// SDL will break our main function in yuzu-cmd if we don't define this before adding SDL.h
5#define SDL_MAIN_HANDLED
6#include <SDL.h>
7
8#include "input_common/main.h"
9#include "sdl_config.h"
10
11const std::array<int, Settings::NativeButton::NumButtons> SdlConfig::default_buttons = {
12 SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_T,
13 SDL_SCANCODE_G, SDL_SCANCODE_F, SDL_SCANCODE_H, SDL_SCANCODE_Q, SDL_SCANCODE_W,
14 SDL_SCANCODE_M, SDL_SCANCODE_N, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_B,
15};
16
17const std::array<int, Settings::NativeMotion::NumMotions> SdlConfig::default_motions = {
18 SDL_SCANCODE_7,
19 SDL_SCANCODE_8,
20};
21
22const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> SdlConfig::default_analogs{
23 {
24 {
25 SDL_SCANCODE_UP,
26 SDL_SCANCODE_DOWN,
27 SDL_SCANCODE_LEFT,
28 SDL_SCANCODE_RIGHT,
29 },
30 {
31 SDL_SCANCODE_I,
32 SDL_SCANCODE_K,
33 SDL_SCANCODE_J,
34 SDL_SCANCODE_L,
35 },
36 }};
37
38const std::array<int, 2> SdlConfig::default_stick_mod = {
39 SDL_SCANCODE_D,
40 0,
41};
42
43const std::array<int, 2> SdlConfig::default_ringcon_analogs{{
44 0,
45 0,
46}};
47
48SdlConfig::SdlConfig(const std::optional<std::string> config_path) {
49 Initialize(config_path);
50 ReadSdlValues();
51 SaveSdlValues();
52}
53
54SdlConfig::~SdlConfig() {
55 if (global) {
56 SdlConfig::SaveAllValues();
57 }
58}
59
60void SdlConfig::ReloadAllValues() {
61 Reload();
62 ReadSdlValues();
63 SaveSdlValues();
64}
65
66void SdlConfig::SaveAllValues() {
67 Save();
68 SaveSdlValues();
69}
70
71void SdlConfig::ReadSdlValues() {
72 ReadSdlControlValues();
73}
74
75void SdlConfig::ReadSdlControlValues() {
76 BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
77
78 Settings::values.players.SetGlobal(!IsCustomConfig());
79 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
80 ReadSdlPlayerValues(p);
81 }
82 if (IsCustomConfig()) {
83 EndGroup();
84 return;
85 }
86 ReadDebugControlValues();
87 ReadHidbusValues();
88
89 EndGroup();
90}
91
92void SdlConfig::ReadSdlPlayerValues(const std::size_t player_index) {
93 std::string player_prefix;
94 if (type != ConfigType::InputProfile) {
95 player_prefix.append("player_").append(ToString(player_index)).append("_");
96 }
97
98 auto& player = Settings::values.players.GetValue()[player_index];
99 if (IsCustomConfig()) {
100 const auto profile_name =
101 ReadStringSetting(std::string(player_prefix).append("profile_name"));
102 if (profile_name.empty()) {
103 // Use the global input config
104 player = Settings::values.players.GetValue(true)[player_index];
105 return;
106 }
107 }
108
109 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
110 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
111 auto& player_buttons = player.buttons[i];
112
113 player_buttons = ReadStringSetting(
114 std::string(player_prefix).append(Settings::NativeButton::mapping[i]), default_param);
115 if (player_buttons.empty()) {
116 player_buttons = default_param;
117 }
118 }
119
120 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
121 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
122 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
123 default_analogs[i][3], default_stick_mod[i], 0.5f);
124 auto& player_analogs = player.analogs[i];
125
126 player_analogs = ReadStringSetting(
127 std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]), default_param);
128 if (player_analogs.empty()) {
129 player_analogs = default_param;
130 }
131 }
132
133 for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
134 const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
135 auto& player_motions = player.motions[i];
136
137 player_motions = ReadStringSetting(
138 std::string(player_prefix).append(Settings::NativeMotion::mapping[i]), default_param);
139 if (player_motions.empty()) {
140 player_motions = default_param;
141 }
142 }
143}
144
145void SdlConfig::ReadDebugControlValues() {
146 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
147 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
148 auto& debug_pad_buttons = Settings::values.debug_pad_buttons[i];
149 debug_pad_buttons = ReadStringSetting(
150 std::string("debug_pad_").append(Settings::NativeButton::mapping[i]), default_param);
151 if (debug_pad_buttons.empty()) {
152 debug_pad_buttons = default_param;
153 }
154 }
155 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
156 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
157 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
158 default_analogs[i][3], default_stick_mod[i], 0.5f);
159 auto& debug_pad_analogs = Settings::values.debug_pad_analogs[i];
160 debug_pad_analogs = ReadStringSetting(
161 std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]), default_param);
162 if (debug_pad_analogs.empty()) {
163 debug_pad_analogs = default_param;
164 }
165 }
166}
167
168void SdlConfig::ReadHidbusValues() {
169 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
170 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
171 auto& ringcon_analogs = Settings::values.ringcon_analogs;
172
173 ringcon_analogs = ReadStringSetting(std::string("ring_controller"), default_param);
174 if (ringcon_analogs.empty()) {
175 ringcon_analogs = default_param;
176 }
177}
178
179void SdlConfig::SaveSdlValues() {
180 SaveSdlControlValues();
181
182 WriteToIni();
183}
184
185void SdlConfig::SaveSdlControlValues() {
186 BeginGroup(Settings::TranslateCategory(Settings::Category::Controls));
187
188 Settings::values.players.SetGlobal(!IsCustomConfig());
189 for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) {
190 SaveSdlPlayerValues(p);
191 }
192 if (IsCustomConfig()) {
193 EndGroup();
194 return;
195 }
196 SaveDebugControlValues();
197 SaveHidbusValues();
198
199 EndGroup();
200}
201
202void SdlConfig::SaveSdlPlayerValues(const std::size_t player_index) {
203 std::string player_prefix;
204 if (type != ConfigType::InputProfile) {
205 player_prefix = std::string("player_").append(ToString(player_index)).append("_");
206 }
207
208 const auto& player = Settings::values.players.GetValue()[player_index];
209 if (IsCustomConfig() && player.profile_name.empty()) {
210 // No custom profile selected
211 return;
212 }
213
214 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
215 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
216 WriteSetting(std::string(player_prefix).append(Settings::NativeButton::mapping[i]),
217 player.buttons[i], std::make_optional(default_param));
218 }
219 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
220 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
221 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
222 default_analogs[i][3], default_stick_mod[i], 0.5f);
223 WriteSetting(std::string(player_prefix).append(Settings::NativeAnalog::mapping[i]),
224 player.analogs[i], std::make_optional(default_param));
225 }
226 for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
227 const std::string default_param = InputCommon::GenerateKeyboardParam(default_motions[i]);
228 WriteSetting(std::string(player_prefix).append(Settings::NativeMotion::mapping[i]),
229 player.motions[i], std::make_optional(default_param));
230 }
231}
232
233void SdlConfig::SaveDebugControlValues() {
234 for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) {
235 const std::string default_param = InputCommon::GenerateKeyboardParam(default_buttons[i]);
236 WriteSetting(std::string("debug_pad_").append(Settings::NativeButton::mapping[i]),
237 Settings::values.debug_pad_buttons[i], std::make_optional(default_param));
238 }
239 for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
240 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
241 default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
242 default_analogs[i][3], default_stick_mod[i], 0.5f);
243 WriteSetting(std::string("debug_pad_").append(Settings::NativeAnalog::mapping[i]),
244 Settings::values.debug_pad_analogs[i], std::make_optional(default_param));
245 }
246}
247
248void SdlConfig::SaveHidbusValues() {
249 const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
250 0, 0, default_ringcon_analogs[0], default_ringcon_analogs[1], 0, 0.05f);
251 WriteSetting(std::string("ring_controller"), Settings::values.ringcon_analogs,
252 std::make_optional(default_param));
253}
254
255std::vector<Settings::BasicSetting*>& SdlConfig::FindRelevantList(Settings::Category category) {
256 return Settings::values.linkage.by_category[category];
257}
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 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "frontend_common/config.h"
7
8class SdlConfig final : public Config {
9public:
10 explicit SdlConfig(std::optional<std::string> config_path);
11 ~SdlConfig() override;
12
13 void ReloadAllValues() override;
14 void SaveAllValues() override;
15
16protected:
17 void ReadSdlValues();
18 void ReadSdlPlayerValues(std::size_t player_index);
19 void ReadSdlControlValues();
20 void ReadHidbusValues() override;
21 void ReadDebugControlValues() override;
22 void ReadPathValues() override {}
23 void ReadShortcutValues() override {}
24 void ReadUIValues() override {}
25 void ReadUIGamelistValues() override {}
26 void ReadUILayoutValues() override {}
27 void ReadMultiplayerValues() override {}
28
29 void SaveSdlValues();
30 void SaveSdlPlayerValues(std::size_t player_index);
31 void SaveSdlControlValues();
32 void SaveHidbusValues() override;
33 void SaveDebugControlValues() override;
34 void SavePathValues() override {}
35 void SaveShortcutValues() override {}
36 void SaveUIValues() override {}
37 void SaveUIGamelistValues() override {}
38 void SaveUILayoutValues() override {}
39 void SaveMultiplayerValues() override {}
40
41 std::vector<Settings::BasicSetting*>& FindRelevantList(Settings::Category category) override;
42
43public:
44 static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
45 static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
46 static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
47 static const std::array<int, 2> default_stick_mod;
48 static const std::array<int, 2> default_ringcon_analogs;
49};
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 @@
29#include "core/hle/service/filesystem/filesystem.h" 29#include "core/hle/service/filesystem/filesystem.h"
30#include "core/loader/loader.h" 30#include "core/loader/loader.h"
31#include "core/telemetry_session.h" 31#include "core/telemetry_session.h"
32#include "frontend_common/config.h"
32#include "input_common/main.h" 33#include "input_common/main.h"
33#include "network/network.h" 34#include "network/network.h"
35#include "sdl_config.h"
34#include "video_core/renderer_base.h" 36#include "video_core/renderer_base.h"
35#include "yuzu_cmd/config.h"
36#include "yuzu_cmd/emu_window/emu_window_sdl2.h" 37#include "yuzu_cmd/emu_window/emu_window_sdl2.h"
37#include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" 38#include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h"
38#include "yuzu_cmd/emu_window/emu_window_sdl2_null.h" 39#include "yuzu_cmd/emu_window/emu_window_sdl2_null.h"
@@ -300,7 +301,7 @@ int main(int argc, char** argv) {
300 } 301 }
301 } 302 }
302 303
303 Config config{config_path}; 304 SdlConfig config{config_path};
304 305
305 // apply the log_filter setting 306 // apply the log_filter setting
306 // the logger was initialized before and doesn't pick up the filter on its own 307 // the logger was initialized before and doesn't pick up the filter on its own