diff options
111 files changed, 3018 insertions, 1593 deletions
diff --git a/.ci/yuzu-mainline-step2.yml b/.ci/yuzu-mainline-step2.yml index 8bb0572f5..825be121a 100644 --- a/.ci/yuzu-mainline-step2.yml +++ b/.ci/yuzu-mainline-step2.yml | |||
| @@ -33,7 +33,6 @@ stages: | |||
| 33 | cache: 'true' | 33 | cache: 'true' |
| 34 | version: $(DisplayVersion) | 34 | version: $(DisplayVersion) |
| 35 | - stage: build_win | 35 | - stage: build_win |
| 36 | dependsOn: format | ||
| 37 | displayName: 'build-windows' | 36 | displayName: 'build-windows' |
| 38 | jobs: | 37 | jobs: |
| 39 | - job: build | 38 | - job: build |
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 b7556e353..1c9fb0675 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 | |||
| @@ -21,6 +21,8 @@ import org.yuzu.yuzu_emu.utils.DocumentsTree | |||
| 21 | import org.yuzu.yuzu_emu.utils.FileUtil | 21 | import org.yuzu.yuzu_emu.utils.FileUtil |
| 22 | import org.yuzu.yuzu_emu.utils.Log | 22 | import org.yuzu.yuzu_emu.utils.Log |
| 23 | import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable | 23 | import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable |
| 24 | import org.yuzu.yuzu_emu.model.InstallResult | ||
| 25 | import org.yuzu.yuzu_emu.model.Patch | ||
| 24 | 26 | ||
| 25 | /** | 27 | /** |
| 26 | * Class which contains methods that interact | 28 | * Class which contains methods that interact |
| @@ -235,9 +237,12 @@ object NativeLibrary { | |||
| 235 | /** | 237 | /** |
| 236 | * Installs a nsp or xci file to nand | 238 | * Installs a nsp or xci file to nand |
| 237 | * @param filename String representation of file uri | 239 | * @param filename String representation of file uri |
| 238 | * @param extension Lowercase string representation of file extension without "." | 240 | * @return int representation of [InstallResult] |
| 239 | */ | 241 | */ |
| 240 | external fun installFileToNand(filename: String, extension: String): Int | 242 | external fun installFileToNand( |
| 243 | filename: String, | ||
| 244 | callback: (max: Long, progress: Long) -> Boolean | ||
| 245 | ): Int | ||
| 241 | 246 | ||
| 242 | external fun doesUpdateMatchProgram(programId: String, updatePath: String): Boolean | 247 | external fun doesUpdateMatchProgram(programId: String, updatePath: String): Boolean |
| 243 | 248 | ||
| @@ -535,9 +540,29 @@ object NativeLibrary { | |||
| 535 | * | 540 | * |
| 536 | * @param path Path to game file. Can be a [Uri]. | 541 | * @param path Path to game file. Can be a [Uri]. |
| 537 | * @param programId String representation of a game's program ID | 542 | * @param programId String representation of a game's program ID |
| 538 | * @return Array of pairs where the first value is the name of an addon and the second is the version | 543 | * @return Array of available patches |
| 539 | */ | 544 | */ |
| 540 | external fun getAddonsForFile(path: String, programId: String): Array<Pair<String, String>>? | 545 | external fun getPatchesForFile(path: String, programId: String): Array<Patch>? |
| 546 | |||
| 547 | /** | ||
| 548 | * Removes an update for a given [programId] | ||
| 549 | * @param programId String representation of a game's program ID | ||
| 550 | */ | ||
| 551 | external fun removeUpdate(programId: String) | ||
| 552 | |||
| 553 | /** | ||
| 554 | * Removes all DLC for a [programId] | ||
| 555 | * @param programId String representation of a game's program ID | ||
| 556 | */ | ||
| 557 | external fun removeDLC(programId: String) | ||
| 558 | |||
| 559 | /** | ||
| 560 | * Removes a mod installed for a given [programId] | ||
| 561 | * @param programId String representation of a game's program ID | ||
| 562 | * @param name The name of a mod as given by [getPatchesForFile]. This corresponds with the name | ||
| 563 | * of the mod's directory in a game's load folder. | ||
| 564 | */ | ||
| 565 | external fun removeMod(programId: String, name: String) | ||
| 541 | 566 | ||
| 542 | /** | 567 | /** |
| 543 | * Gets the save location for a specific game | 568 | * Gets the save location for a specific game |
| @@ -609,15 +634,4 @@ object NativeLibrary { | |||
| 609 | const val RELEASED = 0 | 634 | const val RELEASED = 0 |
| 610 | const val PRESSED = 1 | 635 | const val PRESSED = 1 |
| 611 | } | 636 | } |
| 612 | |||
| 613 | /** | ||
| 614 | * Result from installFileToNand | ||
| 615 | */ | ||
| 616 | object InstallFileToNandResult { | ||
| 617 | const val Success = 0 | ||
| 618 | const val SuccessFileOverwritten = 1 | ||
| 619 | const val Error = 2 | ||
| 620 | const val ErrorBaseGame = 3 | ||
| 621 | const val ErrorFilenameExtension = 4 | ||
| 622 | } | ||
| 623 | } | 637 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index 93c8ce922..9b08f008d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt | |||
| @@ -49,7 +49,6 @@ import org.yuzu.yuzu_emu.utils.ForegroundService | |||
| 49 | import org.yuzu.yuzu_emu.utils.InputHandler | 49 | import org.yuzu.yuzu_emu.utils.InputHandler |
| 50 | import org.yuzu.yuzu_emu.utils.Log | 50 | import org.yuzu.yuzu_emu.utils.Log |
| 51 | import org.yuzu.yuzu_emu.utils.MemoryUtil | 51 | import org.yuzu.yuzu_emu.utils.MemoryUtil |
| 52 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 53 | import org.yuzu.yuzu_emu.utils.NfcReader | 52 | import org.yuzu.yuzu_emu.utils.NfcReader |
| 54 | import org.yuzu.yuzu_emu.utils.ThemeHelper | 53 | import org.yuzu.yuzu_emu.utils.ThemeHelper |
| 55 | import java.text.NumberFormat | 54 | import java.text.NumberFormat |
| @@ -171,11 +170,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 171 | stopMotionSensorListener() | 170 | stopMotionSensorListener() |
| 172 | } | 171 | } |
| 173 | 172 | ||
| 174 | override fun onStop() { | ||
| 175 | super.onStop() | ||
| 176 | NativeConfig.saveGlobalConfig() | ||
| 177 | } | ||
| 178 | |||
| 179 | override fun onUserLeaveHint() { | 173 | override fun onUserLeaveHint() { |
| 180 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { | 174 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { |
| 181 | if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) { | 175 | if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt index 94c151325..ff254d9b7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt | |||
| @@ -6,27 +6,32 @@ package org.yuzu.yuzu_emu.adapters | |||
| 6 | import android.view.LayoutInflater | 6 | import android.view.LayoutInflater |
| 7 | import android.view.ViewGroup | 7 | import android.view.ViewGroup |
| 8 | import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding | 8 | import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding |
| 9 | import org.yuzu.yuzu_emu.model.Addon | 9 | import org.yuzu.yuzu_emu.model.Patch |
| 10 | import org.yuzu.yuzu_emu.model.AddonViewModel | ||
| 10 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder | 11 | import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder |
| 11 | 12 | ||
| 12 | class AddonAdapter : AbstractDiffAdapter<Addon, AddonAdapter.AddonViewHolder>() { | 13 | class AddonAdapter(val addonViewModel: AddonViewModel) : |
| 14 | AbstractDiffAdapter<Patch, AddonAdapter.AddonViewHolder>() { | ||
| 13 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder { | 15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder { |
| 14 | ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false) | 16 | ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false) |
| 15 | .also { return AddonViewHolder(it) } | 17 | .also { return AddonViewHolder(it) } |
| 16 | } | 18 | } |
| 17 | 19 | ||
| 18 | inner class AddonViewHolder(val binding: ListItemAddonBinding) : | 20 | inner class AddonViewHolder(val binding: ListItemAddonBinding) : |
| 19 | AbstractViewHolder<Addon>(binding) { | 21 | AbstractViewHolder<Patch>(binding) { |
| 20 | override fun bind(model: Addon) { | 22 | override fun bind(model: Patch) { |
| 21 | binding.root.setOnClickListener { | 23 | binding.root.setOnClickListener { |
| 22 | binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked | 24 | binding.addonCheckbox.isChecked = !binding.addonCheckbox.isChecked |
| 23 | } | 25 | } |
| 24 | binding.title.text = model.title | 26 | binding.title.text = model.name |
| 25 | binding.version.text = model.version | 27 | binding.version.text = model.version |
| 26 | binding.addonSwitch.setOnCheckedChangeListener { _, checked -> | 28 | binding.addonCheckbox.setOnCheckedChangeListener { _, checked -> |
| 27 | model.enabled = checked | 29 | model.enabled = checked |
| 28 | } | 30 | } |
| 29 | binding.addonSwitch.isChecked = model.enabled | 31 | binding.addonCheckbox.isChecked = model.enabled |
| 32 | binding.buttonDelete.setOnClickListener { | ||
| 33 | addonViewModel.setAddonToDelete(model) | ||
| 34 | } | ||
| 30 | } | 35 | } |
| 31 | } | 36 | } |
| 32 | } | 37 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt index 816336820..adb65812c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddonsFragment.kt | |||
| @@ -74,7 +74,7 @@ class AddonsFragment : Fragment() { | |||
| 74 | 74 | ||
| 75 | binding.listAddons.apply { | 75 | binding.listAddons.apply { |
| 76 | layoutManager = LinearLayoutManager(requireContext()) | 76 | layoutManager = LinearLayoutManager(requireContext()) |
| 77 | adapter = AddonAdapter() | 77 | adapter = AddonAdapter(addonViewModel) |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | viewLifecycleOwner.lifecycleScope.apply { | 80 | viewLifecycleOwner.lifecycleScope.apply { |
| @@ -110,6 +110,21 @@ class AddonsFragment : Fragment() { | |||
| 110 | } | 110 | } |
| 111 | } | 111 | } |
| 112 | } | 112 | } |
| 113 | launch { | ||
| 114 | repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
| 115 | addonViewModel.addonToDelete.collect { | ||
| 116 | if (it != null) { | ||
| 117 | MessageDialogFragment.newInstance( | ||
| 118 | requireActivity(), | ||
| 119 | titleId = R.string.confirm_uninstall, | ||
| 120 | descriptionId = R.string.confirm_uninstall_description, | ||
| 121 | positiveAction = { addonViewModel.onDeleteAddon(it) } | ||
| 122 | ).show(parentFragmentManager, MessageDialogFragment.TAG) | ||
| 123 | addonViewModel.setAddonToDelete(null) | ||
| 124 | } | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | ||
| 113 | } | 128 | } |
| 114 | 129 | ||
| 115 | binding.buttonInstall.setOnClickListener { | 130 | binding.buttonInstall.setOnClickListener { |
| @@ -156,22 +171,22 @@ class AddonsFragment : Fragment() { | |||
| 156 | descriptionId = R.string.invalid_directory_description | 171 | descriptionId = R.string.invalid_directory_description |
| 157 | ) | 172 | ) |
| 158 | if (isValid) { | 173 | if (isValid) { |
| 159 | IndeterminateProgressDialogFragment.newInstance( | 174 | ProgressDialogFragment.newInstance( |
| 160 | requireActivity(), | 175 | requireActivity(), |
| 161 | R.string.installing_game_content, | 176 | R.string.installing_game_content, |
| 162 | false | 177 | false |
| 163 | ) { | 178 | ) { progressCallback, _ -> |
| 164 | val parentDirectoryName = externalAddonDirectory.name | 179 | val parentDirectoryName = externalAddonDirectory.name |
| 165 | val internalAddonDirectory = | 180 | val internalAddonDirectory = |
| 166 | File(args.game.addonDir + parentDirectoryName) | 181 | File(args.game.addonDir + parentDirectoryName) |
| 167 | try { | 182 | try { |
| 168 | externalAddonDirectory.copyFilesTo(internalAddonDirectory) | 183 | externalAddonDirectory.copyFilesTo(internalAddonDirectory, progressCallback) |
| 169 | } catch (_: Exception) { | 184 | } catch (_: Exception) { |
| 170 | return@newInstance errorMessage | 185 | return@newInstance errorMessage |
| 171 | } | 186 | } |
| 172 | addonViewModel.refreshAddons() | 187 | addonViewModel.refreshAddons() |
| 173 | return@newInstance getString(R.string.addon_installed_successfully) | 188 | return@newInstance getString(R.string.addon_installed_successfully) |
| 174 | }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG) | 189 | }.show(parentFragmentManager, ProgressDialogFragment.TAG) |
| 175 | } else { | 190 | } else { |
| 176 | errorMessage.show(parentFragmentManager, MessageDialogFragment.TAG) | 191 | errorMessage.show(parentFragmentManager, MessageDialogFragment.TAG) |
| 177 | } | 192 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt index 9dabb9c41..6c758d80b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt | |||
| @@ -173,11 +173,11 @@ class DriverManagerFragment : Fragment() { | |||
| 173 | return@registerForActivityResult | 173 | return@registerForActivityResult |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | IndeterminateProgressDialogFragment.newInstance( | 176 | ProgressDialogFragment.newInstance( |
| 177 | requireActivity(), | 177 | requireActivity(), |
| 178 | R.string.installing_driver, | 178 | R.string.installing_driver, |
| 179 | false | 179 | false |
| 180 | ) { | 180 | ) { _, _ -> |
| 181 | val driverPath = | 181 | val driverPath = |
| 182 | "${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(result)}" | 182 | "${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(result)}" |
| 183 | val driverFile = File(driverPath) | 183 | val driverFile = File(driverPath) |
| @@ -213,6 +213,6 @@ class DriverManagerFragment : Fragment() { | |||
| 213 | } | 213 | } |
| 214 | } | 214 | } |
| 215 | return@newInstance Any() | 215 | return@newInstance Any() |
| 216 | }.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG) | 216 | }.show(childFragmentManager, ProgressDialogFragment.TAG) |
| 217 | } | 217 | } |
| 218 | } | 218 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 9efc1705d..47767454a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt | |||
| @@ -554,6 +554,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 554 | findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean() | 554 | findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean() |
| 555 | } | 555 | } |
| 556 | 556 | ||
| 557 | popup.setOnDismissListener { NativeConfig.saveGlobalConfig() } | ||
| 557 | popup.setOnMenuItemClickListener { | 558 | popup.setOnMenuItemClickListener { |
| 558 | when (it.itemId) { | 559 | when (it.itemId) { |
| 559 | R.id.menu_toggle_fps -> { | 560 | R.id.menu_toggle_fps -> { |
| @@ -720,7 +721,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { | |||
| 720 | MaterialAlertDialogBuilder(requireContext()) | 721 | MaterialAlertDialogBuilder(requireContext()) |
| 721 | .setTitle(R.string.emulation_control_adjust) | 722 | .setTitle(R.string.emulation_control_adjust) |
| 722 | .setView(adjustBinding.root) | 723 | .setView(adjustBinding.root) |
| 723 | .setPositiveButton(android.R.string.ok, null) | 724 | .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> |
| 725 | NativeConfig.saveGlobalConfig() | ||
| 726 | } | ||
| 724 | .setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int -> | 727 | .setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int -> |
| 725 | setControlScale(50) | 728 | setControlScale(50) |
| 726 | setControlOpacity(100) | 729 | setControlOpacity(100) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt index b04d1208f..83a845434 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/GamePropertiesFragment.kt | |||
| @@ -44,7 +44,6 @@ import org.yuzu.yuzu_emu.utils.FileUtil | |||
| 44 | import org.yuzu.yuzu_emu.utils.GameIconUtils | 44 | import org.yuzu.yuzu_emu.utils.GameIconUtils |
| 45 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper | 45 | import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
| 46 | import org.yuzu.yuzu_emu.utils.MemoryUtil | 46 | import org.yuzu.yuzu_emu.utils.MemoryUtil |
| 47 | import java.io.BufferedInputStream | ||
| 48 | import java.io.BufferedOutputStream | 47 | import java.io.BufferedOutputStream |
| 49 | import java.io.File | 48 | import java.io.File |
| 50 | 49 | ||
| @@ -357,27 +356,17 @@ class GamePropertiesFragment : Fragment() { | |||
| 357 | return@registerForActivityResult | 356 | return@registerForActivityResult |
| 358 | } | 357 | } |
| 359 | 358 | ||
| 360 | val inputZip = requireContext().contentResolver.openInputStream(result) | ||
| 361 | val savesFolder = File(args.game.saveDir) | 359 | val savesFolder = File(args.game.saveDir) |
| 362 | val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/") | 360 | val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/") |
| 363 | cacheSaveDir.mkdir() | 361 | cacheSaveDir.mkdir() |
| 364 | 362 | ||
| 365 | if (inputZip == null) { | 363 | ProgressDialogFragment.newInstance( |
| 366 | Toast.makeText( | ||
| 367 | YuzuApplication.appContext, | ||
| 368 | getString(R.string.fatal_error), | ||
| 369 | Toast.LENGTH_LONG | ||
| 370 | ).show() | ||
| 371 | return@registerForActivityResult | ||
| 372 | } | ||
| 373 | |||
| 374 | IndeterminateProgressDialogFragment.newInstance( | ||
| 375 | requireActivity(), | 364 | requireActivity(), |
| 376 | R.string.save_files_importing, | 365 | R.string.save_files_importing, |
| 377 | false | 366 | false |
| 378 | ) { | 367 | ) { _, _ -> |
| 379 | try { | 368 | try { |
| 380 | FileUtil.unzipToInternalStorage(BufferedInputStream(inputZip), cacheSaveDir) | 369 | FileUtil.unzipToInternalStorage(result.toString(), cacheSaveDir) |
| 381 | val files = cacheSaveDir.listFiles() | 370 | val files = cacheSaveDir.listFiles() |
| 382 | var savesFolderFile: File? = null | 371 | var savesFolderFile: File? = null |
| 383 | if (files != null) { | 372 | if (files != null) { |
| @@ -422,7 +411,7 @@ class GamePropertiesFragment : Fragment() { | |||
| 422 | Toast.LENGTH_LONG | 411 | Toast.LENGTH_LONG |
| 423 | ).show() | 412 | ).show() |
| 424 | } | 413 | } |
| 425 | }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG) | 414 | }.show(parentFragmentManager, ProgressDialogFragment.TAG) |
| 426 | } | 415 | } |
| 427 | 416 | ||
| 428 | /** | 417 | /** |
| @@ -436,11 +425,11 @@ class GamePropertiesFragment : Fragment() { | |||
| 436 | return@registerForActivityResult | 425 | return@registerForActivityResult |
| 437 | } | 426 | } |
| 438 | 427 | ||
| 439 | IndeterminateProgressDialogFragment.newInstance( | 428 | ProgressDialogFragment.newInstance( |
| 440 | requireActivity(), | 429 | requireActivity(), |
| 441 | R.string.save_files_exporting, | 430 | R.string.save_files_exporting, |
| 442 | false | 431 | false |
| 443 | ) { | 432 | ) { _, _ -> |
| 444 | val saveLocation = args.game.saveDir | 433 | val saveLocation = args.game.saveDir |
| 445 | val zipResult = FileUtil.zipFromInternalStorage( | 434 | val zipResult = FileUtil.zipFromInternalStorage( |
| 446 | File(saveLocation), | 435 | File(saveLocation), |
| @@ -452,6 +441,6 @@ class GamePropertiesFragment : Fragment() { | |||
| 452 | TaskState.Completed -> getString(R.string.export_success) | 441 | TaskState.Completed -> getString(R.string.export_success) |
| 453 | TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed) | 442 | TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed) |
| 454 | } | 443 | } |
| 455 | }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG) | 444 | }.show(parentFragmentManager, ProgressDialogFragment.TAG) |
| 456 | } | 445 | } |
| 457 | } | 446 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt index 5b4bf2c9f..7df8e6bf4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt | |||
| @@ -34,7 +34,6 @@ import org.yuzu.yuzu_emu.model.TaskState | |||
| 34 | import org.yuzu.yuzu_emu.ui.main.MainActivity | 34 | import org.yuzu.yuzu_emu.ui.main.MainActivity |
| 35 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization | 35 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization |
| 36 | import org.yuzu.yuzu_emu.utils.FileUtil | 36 | import org.yuzu.yuzu_emu.utils.FileUtil |
| 37 | import java.io.BufferedInputStream | ||
| 38 | import java.io.BufferedOutputStream | 37 | import java.io.BufferedOutputStream |
| 39 | import java.io.File | 38 | import java.io.File |
| 40 | import java.math.BigInteger | 39 | import java.math.BigInteger |
| @@ -195,26 +194,20 @@ class InstallableFragment : Fragment() { | |||
| 195 | return@registerForActivityResult | 194 | return@registerForActivityResult |
| 196 | } | 195 | } |
| 197 | 196 | ||
| 198 | val inputZip = requireContext().contentResolver.openInputStream(result) | ||
| 199 | val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/") | 197 | val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/") |
| 200 | cacheSaveDir.mkdir() | 198 | cacheSaveDir.mkdir() |
| 201 | 199 | ||
| 202 | if (inputZip == null) { | 200 | ProgressDialogFragment.newInstance( |
| 203 | Toast.makeText( | ||
| 204 | YuzuApplication.appContext, | ||
| 205 | getString(R.string.fatal_error), | ||
| 206 | Toast.LENGTH_LONG | ||
| 207 | ).show() | ||
| 208 | return@registerForActivityResult | ||
| 209 | } | ||
| 210 | |||
| 211 | IndeterminateProgressDialogFragment.newInstance( | ||
| 212 | requireActivity(), | 201 | requireActivity(), |
| 213 | R.string.save_files_importing, | 202 | R.string.save_files_importing, |
| 214 | false | 203 | false |
| 215 | ) { | 204 | ) { progressCallback, _ -> |
| 216 | try { | 205 | try { |
| 217 | FileUtil.unzipToInternalStorage(BufferedInputStream(inputZip), cacheSaveDir) | 206 | FileUtil.unzipToInternalStorage( |
| 207 | result.toString(), | ||
| 208 | cacheSaveDir, | ||
| 209 | progressCallback | ||
| 210 | ) | ||
| 218 | val files = cacheSaveDir.listFiles() | 211 | val files = cacheSaveDir.listFiles() |
| 219 | var successfulImports = 0 | 212 | var successfulImports = 0 |
| 220 | var failedImports = 0 | 213 | var failedImports = 0 |
| @@ -287,7 +280,7 @@ class InstallableFragment : Fragment() { | |||
| 287 | Toast.LENGTH_LONG | 280 | Toast.LENGTH_LONG |
| 288 | ).show() | 281 | ).show() |
| 289 | } | 282 | } |
| 290 | }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG) | 283 | }.show(parentFragmentManager, ProgressDialogFragment.TAG) |
| 291 | } | 284 | } |
| 292 | 285 | ||
| 293 | private val exportSaves = registerForActivityResult( | 286 | private val exportSaves = registerForActivityResult( |
| @@ -297,11 +290,11 @@ class InstallableFragment : Fragment() { | |||
| 297 | return@registerForActivityResult | 290 | return@registerForActivityResult |
| 298 | } | 291 | } |
| 299 | 292 | ||
| 300 | IndeterminateProgressDialogFragment.newInstance( | 293 | ProgressDialogFragment.newInstance( |
| 301 | requireActivity(), | 294 | requireActivity(), |
| 302 | R.string.save_files_exporting, | 295 | R.string.save_files_exporting, |
| 303 | false | 296 | false |
| 304 | ) { | 297 | ) { _, _ -> |
| 305 | val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/") | 298 | val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/") |
| 306 | cacheSaveDir.mkdir() | 299 | cacheSaveDir.mkdir() |
| 307 | 300 | ||
| @@ -338,6 +331,6 @@ class InstallableFragment : Fragment() { | |||
| 338 | TaskState.Completed -> getString(R.string.export_success) | 331 | TaskState.Completed -> getString(R.string.export_success) |
| 339 | TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed) | 332 | TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed) |
| 340 | } | 333 | } |
| 341 | }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG) | 334 | }.show(parentFragmentManager, ProgressDialogFragment.TAG) |
| 342 | } | 335 | } |
| 343 | } | 336 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt index 8847e5531..d201cb80c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt | |||
| @@ -23,11 +23,13 @@ import org.yuzu.yuzu_emu.R | |||
| 23 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding | 23 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding |
| 24 | import org.yuzu.yuzu_emu.model.TaskViewModel | 24 | import org.yuzu.yuzu_emu.model.TaskViewModel |
| 25 | 25 | ||
| 26 | class IndeterminateProgressDialogFragment : DialogFragment() { | 26 | class ProgressDialogFragment : DialogFragment() { |
| 27 | private val taskViewModel: TaskViewModel by activityViewModels() | 27 | private val taskViewModel: TaskViewModel by activityViewModels() |
| 28 | 28 | ||
| 29 | private lateinit var binding: DialogProgressBarBinding | 29 | private lateinit var binding: DialogProgressBarBinding |
| 30 | 30 | ||
| 31 | private val PROGRESS_BAR_RESOLUTION = 1000 | ||
| 32 | |||
| 31 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { | 33 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { |
| 32 | val titleId = requireArguments().getInt(TITLE) | 34 | val titleId = requireArguments().getInt(TITLE) |
| 33 | val cancellable = requireArguments().getBoolean(CANCELLABLE) | 35 | val cancellable = requireArguments().getBoolean(CANCELLABLE) |
| @@ -61,6 +63,7 @@ class IndeterminateProgressDialogFragment : DialogFragment() { | |||
| 61 | 63 | ||
| 62 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 64 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 63 | super.onViewCreated(view, savedInstanceState) | 65 | super.onViewCreated(view, savedInstanceState) |
| 66 | binding.message.isSelected = true | ||
| 64 | viewLifecycleOwner.lifecycleScope.apply { | 67 | viewLifecycleOwner.lifecycleScope.apply { |
| 65 | launch { | 68 | launch { |
| 66 | repeatOnLifecycle(Lifecycle.State.CREATED) { | 69 | repeatOnLifecycle(Lifecycle.State.CREATED) { |
| @@ -97,6 +100,35 @@ class IndeterminateProgressDialogFragment : DialogFragment() { | |||
| 97 | } | 100 | } |
| 98 | } | 101 | } |
| 99 | } | 102 | } |
| 103 | launch { | ||
| 104 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 105 | taskViewModel.progress.collect { | ||
| 106 | if (it != 0.0) { | ||
| 107 | binding.progressBar.apply { | ||
| 108 | isIndeterminate = false | ||
| 109 | progress = ( | ||
| 110 | (it / taskViewModel.maxProgress.value) * | ||
| 111 | PROGRESS_BAR_RESOLUTION | ||
| 112 | ).toInt() | ||
| 113 | min = 0 | ||
| 114 | max = PROGRESS_BAR_RESOLUTION | ||
| 115 | } | ||
| 116 | } | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | launch { | ||
| 121 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 122 | taskViewModel.message.collect { | ||
| 123 | if (it.isEmpty()) { | ||
| 124 | binding.message.visibility = View.GONE | ||
| 125 | } else { | ||
| 126 | binding.message.visibility = View.VISIBLE | ||
| 127 | binding.message.text = it | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | } | ||
| 100 | } | 132 | } |
| 101 | } | 133 | } |
| 102 | 134 | ||
| @@ -108,6 +140,7 @@ class IndeterminateProgressDialogFragment : DialogFragment() { | |||
| 108 | val negativeButton = alertDialog.getButton(Dialog.BUTTON_NEGATIVE) | 140 | val negativeButton = alertDialog.getButton(Dialog.BUTTON_NEGATIVE) |
| 109 | negativeButton.setOnClickListener { | 141 | negativeButton.setOnClickListener { |
| 110 | alertDialog.setTitle(getString(R.string.cancelling)) | 142 | alertDialog.setTitle(getString(R.string.cancelling)) |
| 143 | binding.progressBar.isIndeterminate = true | ||
| 111 | taskViewModel.setCancelled(true) | 144 | taskViewModel.setCancelled(true) |
| 112 | } | 145 | } |
| 113 | } | 146 | } |
| @@ -122,9 +155,12 @@ class IndeterminateProgressDialogFragment : DialogFragment() { | |||
| 122 | activity: FragmentActivity, | 155 | activity: FragmentActivity, |
| 123 | titleId: Int, | 156 | titleId: Int, |
| 124 | cancellable: Boolean = false, | 157 | cancellable: Boolean = false, |
| 125 | task: suspend () -> Any | 158 | task: suspend ( |
| 126 | ): IndeterminateProgressDialogFragment { | 159 | progressCallback: (max: Long, progress: Long) -> Boolean, |
| 127 | val dialog = IndeterminateProgressDialogFragment() | 160 | messageCallback: (message: String) -> Unit |
| 161 | ) -> Any | ||
| 162 | ): ProgressDialogFragment { | ||
| 163 | val dialog = ProgressDialogFragment() | ||
| 128 | val args = Bundle() | 164 | val args = Bundle() |
| 129 | ViewModelProvider(activity)[TaskViewModel::class.java].task = task | 165 | ViewModelProvider(activity)[TaskViewModel::class.java].task = task |
| 130 | args.putInt(TITLE, titleId) | 166 | args.putInt(TITLE, titleId) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt index 64b295fbd..20b10b1a0 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt | |||
| @@ -136,14 +136,14 @@ class SearchFragment : Fragment() { | |||
| 136 | baseList.filter { | 136 | baseList.filter { |
| 137 | val lastPlayedTime = preferences.getLong(it.keyLastPlayedTime, 0L) | 137 | val lastPlayedTime = preferences.getLong(it.keyLastPlayedTime, 0L) |
| 138 | lastPlayedTime > (System.currentTimeMillis() - 24 * 60 * 60 * 1000) | 138 | lastPlayedTime > (System.currentTimeMillis() - 24 * 60 * 60 * 1000) |
| 139 | } | 139 | }.sortedByDescending { preferences.getLong(it.keyLastPlayedTime, 0L) } |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | R.id.chip_recently_added -> { | 142 | R.id.chip_recently_added -> { |
| 143 | baseList.filter { | 143 | baseList.filter { |
| 144 | val addedTime = preferences.getLong(it.keyAddedToLibraryTime, 0L) | 144 | val addedTime = preferences.getLong(it.keyAddedToLibraryTime, 0L) |
| 145 | addedTime > (System.currentTimeMillis() - 24 * 60 * 60 * 1000) | 145 | addedTime > (System.currentTimeMillis() - 24 * 60 * 60 * 1000) |
| 146 | } | 146 | }.sortedByDescending { preferences.getLong(it.keyAddedToLibraryTime, 0L) } |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | R.id.chip_homebrew -> baseList.filter { it.isHomebrew } | 149 | R.id.chip_homebrew -> baseList.filter { it.isHomebrew } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Addon.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Addon.kt deleted file mode 100644 index ed79a8b02..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Addon.kt +++ /dev/null | |||
| @@ -1,10 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.model | ||
| 5 | |||
| 6 | data class Addon( | ||
| 7 | var enabled: Boolean, | ||
| 8 | val title: String, | ||
| 9 | val version: String | ||
| 10 | ) | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt index 075252f5b..b9c8e49ca 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt | |||
| @@ -15,8 +15,8 @@ import org.yuzu.yuzu_emu.utils.NativeConfig | |||
| 15 | import java.util.concurrent.atomic.AtomicBoolean | 15 | import java.util.concurrent.atomic.AtomicBoolean |
| 16 | 16 | ||
| 17 | class AddonViewModel : ViewModel() { | 17 | class AddonViewModel : ViewModel() { |
| 18 | private val _addonList = MutableStateFlow(mutableListOf<Addon>()) | 18 | private val _patchList = MutableStateFlow(mutableListOf<Patch>()) |
| 19 | val addonList get() = _addonList.asStateFlow() | 19 | val addonList get() = _patchList.asStateFlow() |
| 20 | 20 | ||
| 21 | private val _showModInstallPicker = MutableStateFlow(false) | 21 | private val _showModInstallPicker = MutableStateFlow(false) |
| 22 | val showModInstallPicker get() = _showModInstallPicker.asStateFlow() | 22 | val showModInstallPicker get() = _showModInstallPicker.asStateFlow() |
| @@ -24,6 +24,9 @@ class AddonViewModel : ViewModel() { | |||
| 24 | private val _showModNoticeDialog = MutableStateFlow(false) | 24 | private val _showModNoticeDialog = MutableStateFlow(false) |
| 25 | val showModNoticeDialog get() = _showModNoticeDialog.asStateFlow() | 25 | val showModNoticeDialog get() = _showModNoticeDialog.asStateFlow() |
| 26 | 26 | ||
| 27 | private val _addonToDelete = MutableStateFlow<Patch?>(null) | ||
| 28 | val addonToDelete = _addonToDelete.asStateFlow() | ||
| 29 | |||
| 27 | var game: Game? = null | 30 | var game: Game? = null |
| 28 | 31 | ||
| 29 | private val isRefreshing = AtomicBoolean(false) | 32 | private val isRefreshing = AtomicBoolean(false) |
| @@ -40,36 +43,47 @@ class AddonViewModel : ViewModel() { | |||
| 40 | isRefreshing.set(true) | 43 | isRefreshing.set(true) |
| 41 | viewModelScope.launch { | 44 | viewModelScope.launch { |
| 42 | withContext(Dispatchers.IO) { | 45 | withContext(Dispatchers.IO) { |
| 43 | val addonList = mutableListOf<Addon>() | 46 | val patchList = ( |
| 44 | val disabledAddons = NativeConfig.getDisabledAddons(game!!.programId) | 47 | NativeLibrary.getPatchesForFile(game!!.path, game!!.programId) |
| 45 | NativeLibrary.getAddonsForFile(game!!.path, game!!.programId)?.forEach { | 48 | ?: emptyArray() |
| 46 | val name = it.first.replace("[D] ", "") | 49 | ).toMutableList() |
| 47 | addonList.add(Addon(!disabledAddons.contains(name), name, it.second)) | 50 | patchList.sortBy { it.name } |
| 48 | } | 51 | _patchList.value = patchList |
| 49 | addonList.sortBy { it.title } | ||
| 50 | _addonList.value = addonList | ||
| 51 | isRefreshing.set(false) | 52 | isRefreshing.set(false) |
| 52 | } | 53 | } |
| 53 | } | 54 | } |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 57 | fun setAddonToDelete(patch: Patch?) { | ||
| 58 | _addonToDelete.value = patch | ||
| 59 | } | ||
| 60 | |||
| 61 | fun onDeleteAddon(patch: Patch) { | ||
| 62 | when (PatchType.from(patch.type)) { | ||
| 63 | PatchType.Update -> NativeLibrary.removeUpdate(patch.programId) | ||
| 64 | PatchType.DLC -> NativeLibrary.removeDLC(patch.programId) | ||
| 65 | PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name) | ||
| 66 | } | ||
| 67 | refreshAddons() | ||
| 68 | } | ||
| 69 | |||
| 56 | fun onCloseAddons() { | 70 | fun onCloseAddons() { |
| 57 | if (_addonList.value.isEmpty()) { | 71 | if (_patchList.value.isEmpty()) { |
| 58 | return | 72 | return |
| 59 | } | 73 | } |
| 60 | 74 | ||
| 61 | NativeConfig.setDisabledAddons( | 75 | NativeConfig.setDisabledAddons( |
| 62 | game!!.programId, | 76 | game!!.programId, |
| 63 | _addonList.value.mapNotNull { | 77 | _patchList.value.mapNotNull { |
| 64 | if (it.enabled) { | 78 | if (it.enabled) { |
| 65 | null | 79 | null |
| 66 | } else { | 80 | } else { |
| 67 | it.title | 81 | it.name |
| 68 | } | 82 | } |
| 69 | }.toTypedArray() | 83 | }.toTypedArray() |
| 70 | ) | 84 | ) |
| 71 | NativeConfig.saveGlobalConfig() | 85 | NativeConfig.saveGlobalConfig() |
| 72 | _addonList.value.clear() | 86 | _patchList.value.clear() |
| 73 | game = null | 87 | game = null |
| 74 | } | 88 | } |
| 75 | 89 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/InstallResult.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/InstallResult.kt new file mode 100644 index 000000000..0c3cd0521 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/InstallResult.kt | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.model | ||
| 5 | |||
| 6 | enum class InstallResult(val int: Int) { | ||
| 7 | Success(0), | ||
| 8 | Overwrite(1), | ||
| 9 | Failure(2), | ||
| 10 | BaseInstallAttempted(3); | ||
| 11 | |||
| 12 | companion object { | ||
| 13 | fun from(int: Int): InstallResult = entries.firstOrNull { it.int == int } ?: Success | ||
| 14 | } | ||
| 15 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Patch.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Patch.kt new file mode 100644 index 000000000..25cb9e365 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Patch.kt | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.model | ||
| 5 | |||
| 6 | import androidx.annotation.Keep | ||
| 7 | |||
| 8 | @Keep | ||
| 9 | data class Patch( | ||
| 10 | var enabled: Boolean, | ||
| 11 | val name: String, | ||
| 12 | val version: String, | ||
| 13 | val type: Int, | ||
| 14 | val programId: String, | ||
| 15 | val titleId: String | ||
| 16 | ) | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/PatchType.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/PatchType.kt new file mode 100644 index 000000000..e9a54162b --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/PatchType.kt | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.model | ||
| 5 | |||
| 6 | enum class PatchType(val int: Int) { | ||
| 7 | Update(0), | ||
| 8 | DLC(1), | ||
| 9 | Mod(2); | ||
| 10 | |||
| 11 | companion object { | ||
| 12 | fun from(int: Int): PatchType = entries.firstOrNull { it.int == int } ?: Update | ||
| 13 | } | ||
| 14 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/TaskViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/TaskViewModel.kt index e59c95733..4361eb972 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/TaskViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/TaskViewModel.kt | |||
| @@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope | |||
| 8 | import kotlinx.coroutines.Dispatchers | 8 | import kotlinx.coroutines.Dispatchers |
| 9 | import kotlinx.coroutines.flow.MutableStateFlow | 9 | import kotlinx.coroutines.flow.MutableStateFlow |
| 10 | import kotlinx.coroutines.flow.StateFlow | 10 | import kotlinx.coroutines.flow.StateFlow |
| 11 | import kotlinx.coroutines.flow.asStateFlow | ||
| 11 | import kotlinx.coroutines.launch | 12 | import kotlinx.coroutines.launch |
| 12 | 13 | ||
| 13 | class TaskViewModel : ViewModel() { | 14 | class TaskViewModel : ViewModel() { |
| @@ -23,13 +24,28 @@ class TaskViewModel : ViewModel() { | |||
| 23 | val cancelled: StateFlow<Boolean> get() = _cancelled | 24 | val cancelled: StateFlow<Boolean> get() = _cancelled |
| 24 | private val _cancelled = MutableStateFlow(false) | 25 | private val _cancelled = MutableStateFlow(false) |
| 25 | 26 | ||
| 26 | lateinit var task: suspend () -> Any | 27 | private val _progress = MutableStateFlow(0.0) |
| 28 | val progress = _progress.asStateFlow() | ||
| 29 | |||
| 30 | private val _maxProgress = MutableStateFlow(0.0) | ||
| 31 | val maxProgress = _maxProgress.asStateFlow() | ||
| 32 | |||
| 33 | private val _message = MutableStateFlow("") | ||
| 34 | val message = _message.asStateFlow() | ||
| 35 | |||
| 36 | lateinit var task: suspend ( | ||
| 37 | progressCallback: (max: Long, progress: Long) -> Boolean, | ||
| 38 | messageCallback: (message: String) -> Unit | ||
| 39 | ) -> Any | ||
| 27 | 40 | ||
| 28 | fun clear() { | 41 | fun clear() { |
| 29 | _result.value = Any() | 42 | _result.value = Any() |
| 30 | _isComplete.value = false | 43 | _isComplete.value = false |
| 31 | _isRunning.value = false | 44 | _isRunning.value = false |
| 32 | _cancelled.value = false | 45 | _cancelled.value = false |
| 46 | _progress.value = 0.0 | ||
| 47 | _maxProgress.value = 0.0 | ||
| 48 | _message.value = "" | ||
| 33 | } | 49 | } |
| 34 | 50 | ||
| 35 | fun setCancelled(value: Boolean) { | 51 | fun setCancelled(value: Boolean) { |
| @@ -43,7 +59,16 @@ class TaskViewModel : ViewModel() { | |||
| 43 | _isRunning.value = true | 59 | _isRunning.value = true |
| 44 | 60 | ||
| 45 | viewModelScope.launch(Dispatchers.IO) { | 61 | viewModelScope.launch(Dispatchers.IO) { |
| 46 | val res = task() | 62 | val res = task( |
| 63 | { max, progress -> | ||
| 64 | _maxProgress.value = max.toDouble() | ||
| 65 | _progress.value = progress.toDouble() | ||
| 66 | return@task cancelled.value | ||
| 67 | }, | ||
| 68 | { message -> | ||
| 69 | _message.value = message | ||
| 70 | } | ||
| 71 | ) | ||
| 47 | _result.value = res | 72 | _result.value = res |
| 48 | _isComplete.value = true | 73 | _isComplete.value = true |
| 49 | _isRunning.value = false | 74 | _isRunning.value = false |
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 644289e25..c2cc29961 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 | |||
| @@ -38,12 +38,13 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity | |||
| 38 | import org.yuzu.yuzu_emu.databinding.ActivityMainBinding | 38 | import org.yuzu.yuzu_emu.databinding.ActivityMainBinding |
| 39 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 39 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 40 | import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment | 40 | import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment |
| 41 | import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment | 41 | import org.yuzu.yuzu_emu.fragments.ProgressDialogFragment |
| 42 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment | 42 | import org.yuzu.yuzu_emu.fragments.MessageDialogFragment |
| 43 | import org.yuzu.yuzu_emu.model.AddonViewModel | 43 | import org.yuzu.yuzu_emu.model.AddonViewModel |
| 44 | import org.yuzu.yuzu_emu.model.DriverViewModel | 44 | import org.yuzu.yuzu_emu.model.DriverViewModel |
| 45 | import org.yuzu.yuzu_emu.model.GamesViewModel | 45 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 46 | import org.yuzu.yuzu_emu.model.HomeViewModel | 46 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 47 | import org.yuzu.yuzu_emu.model.InstallResult | ||
| 47 | import org.yuzu.yuzu_emu.model.TaskState | 48 | import org.yuzu.yuzu_emu.model.TaskState |
| 48 | import org.yuzu.yuzu_emu.model.TaskViewModel | 49 | import org.yuzu.yuzu_emu.model.TaskViewModel |
| 49 | import org.yuzu.yuzu_emu.utils.* | 50 | import org.yuzu.yuzu_emu.utils.* |
| @@ -369,26 +370,23 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 369 | return@registerForActivityResult | 370 | return@registerForActivityResult |
| 370 | } | 371 | } |
| 371 | 372 | ||
| 372 | val inputZip = contentResolver.openInputStream(result) | ||
| 373 | if (inputZip == null) { | ||
| 374 | Toast.makeText( | ||
| 375 | applicationContext, | ||
| 376 | getString(R.string.fatal_error), | ||
| 377 | Toast.LENGTH_LONG | ||
| 378 | ).show() | ||
| 379 | return@registerForActivityResult | ||
| 380 | } | ||
| 381 | |||
| 382 | val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") } | 373 | val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") } |
| 383 | 374 | ||
| 384 | val firmwarePath = | 375 | val firmwarePath = |
| 385 | File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/") | 376 | File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/") |
| 386 | val cacheFirmwareDir = File("${cacheDir.path}/registered/") | 377 | val cacheFirmwareDir = File("${cacheDir.path}/registered/") |
| 387 | 378 | ||
| 388 | val task: () -> Any = { | 379 | ProgressDialogFragment.newInstance( |
| 380 | this, | ||
| 381 | R.string.firmware_installing | ||
| 382 | ) { progressCallback, _ -> | ||
| 389 | var messageToShow: Any | 383 | var messageToShow: Any |
| 390 | try { | 384 | try { |
| 391 | FileUtil.unzipToInternalStorage(BufferedInputStream(inputZip), cacheFirmwareDir) | 385 | FileUtil.unzipToInternalStorage( |
| 386 | result.toString(), | ||
| 387 | cacheFirmwareDir, | ||
| 388 | progressCallback | ||
| 389 | ) | ||
| 392 | val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1 | 390 | val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1 |
| 393 | val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2 | 391 | val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2 |
| 394 | messageToShow = if (unfilteredNumOfFiles != filteredNumOfFiles) { | 392 | messageToShow = if (unfilteredNumOfFiles != filteredNumOfFiles) { |
| @@ -404,18 +402,13 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 404 | getString(R.string.save_file_imported_success) | 402 | getString(R.string.save_file_imported_success) |
| 405 | } | 403 | } |
| 406 | } catch (e: Exception) { | 404 | } catch (e: Exception) { |
| 405 | Log.error("[MainActivity] Firmware install failed - ${e.message}") | ||
| 407 | messageToShow = getString(R.string.fatal_error) | 406 | messageToShow = getString(R.string.fatal_error) |
| 408 | } finally { | 407 | } finally { |
| 409 | cacheFirmwareDir.deleteRecursively() | 408 | cacheFirmwareDir.deleteRecursively() |
| 410 | } | 409 | } |
| 411 | messageToShow | 410 | messageToShow |
| 412 | } | 411 | }.show(supportFragmentManager, ProgressDialogFragment.TAG) |
| 413 | |||
| 414 | IndeterminateProgressDialogFragment.newInstance( | ||
| 415 | this, | ||
| 416 | R.string.firmware_installing, | ||
| 417 | task = task | ||
| 418 | ).show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) | ||
| 419 | } | 412 | } |
| 420 | 413 | ||
| 421 | val getAmiiboKey = | 414 | val getAmiiboKey = |
| @@ -474,11 +467,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 474 | return@registerForActivityResult | 467 | return@registerForActivityResult |
| 475 | } | 468 | } |
| 476 | 469 | ||
| 477 | IndeterminateProgressDialogFragment.newInstance( | 470 | ProgressDialogFragment.newInstance( |
| 478 | this@MainActivity, | 471 | this@MainActivity, |
| 479 | R.string.verifying_content, | 472 | R.string.verifying_content, |
| 480 | false | 473 | false |
| 481 | ) { | 474 | ) { _, _ -> |
| 482 | var updatesMatchProgram = true | 475 | var updatesMatchProgram = true |
| 483 | for (document in documents) { | 476 | for (document in documents) { |
| 484 | val valid = NativeLibrary.doesUpdateMatchProgram( | 477 | val valid = NativeLibrary.doesUpdateMatchProgram( |
| @@ -501,44 +494,42 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 501 | positiveAction = { homeViewModel.setContentToInstall(documents) } | 494 | positiveAction = { homeViewModel.setContentToInstall(documents) } |
| 502 | ) | 495 | ) |
| 503 | } | 496 | } |
| 504 | }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) | 497 | }.show(supportFragmentManager, ProgressDialogFragment.TAG) |
| 505 | } | 498 | } |
| 506 | 499 | ||
| 507 | private fun installContent(documents: List<Uri>) { | 500 | private fun installContent(documents: List<Uri>) { |
| 508 | IndeterminateProgressDialogFragment.newInstance( | 501 | ProgressDialogFragment.newInstance( |
| 509 | this@MainActivity, | 502 | this@MainActivity, |
| 510 | R.string.installing_game_content | 503 | R.string.installing_game_content |
| 511 | ) { | 504 | ) { progressCallback, messageCallback -> |
| 512 | var installSuccess = 0 | 505 | var installSuccess = 0 |
| 513 | var installOverwrite = 0 | 506 | var installOverwrite = 0 |
| 514 | var errorBaseGame = 0 | 507 | var errorBaseGame = 0 |
| 515 | var errorExtension = 0 | 508 | var error = 0 |
| 516 | var errorOther = 0 | ||
| 517 | documents.forEach { | 509 | documents.forEach { |
| 510 | messageCallback.invoke(FileUtil.getFilename(it)) | ||
| 518 | when ( | 511 | when ( |
| 519 | NativeLibrary.installFileToNand( | 512 | InstallResult.from( |
| 520 | it.toString(), | 513 | NativeLibrary.installFileToNand( |
| 521 | FileUtil.getExtension(it) | 514 | it.toString(), |
| 515 | progressCallback | ||
| 516 | ) | ||
| 522 | ) | 517 | ) |
| 523 | ) { | 518 | ) { |
| 524 | NativeLibrary.InstallFileToNandResult.Success -> { | 519 | InstallResult.Success -> { |
| 525 | installSuccess += 1 | 520 | installSuccess += 1 |
| 526 | } | 521 | } |
| 527 | 522 | ||
| 528 | NativeLibrary.InstallFileToNandResult.SuccessFileOverwritten -> { | 523 | InstallResult.Overwrite -> { |
| 529 | installOverwrite += 1 | 524 | installOverwrite += 1 |
| 530 | } | 525 | } |
| 531 | 526 | ||
| 532 | NativeLibrary.InstallFileToNandResult.ErrorBaseGame -> { | 527 | InstallResult.BaseInstallAttempted -> { |
| 533 | errorBaseGame += 1 | 528 | errorBaseGame += 1 |
| 534 | } | 529 | } |
| 535 | 530 | ||
| 536 | NativeLibrary.InstallFileToNandResult.ErrorFilenameExtension -> { | 531 | InstallResult.Failure -> { |
| 537 | errorExtension += 1 | 532 | error += 1 |
| 538 | } | ||
| 539 | |||
| 540 | else -> { | ||
| 541 | errorOther += 1 | ||
| 542 | } | 533 | } |
| 543 | } | 534 | } |
| 544 | } | 535 | } |
| @@ -565,7 +556,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 565 | ) | 556 | ) |
| 566 | installResult.append(separator) | 557 | installResult.append(separator) |
| 567 | } | 558 | } |
| 568 | val errorTotal: Int = errorBaseGame + errorExtension + errorOther | 559 | val errorTotal: Int = errorBaseGame + error |
| 569 | if (errorTotal > 0) { | 560 | if (errorTotal > 0) { |
| 570 | installResult.append(separator) | 561 | installResult.append(separator) |
| 571 | installResult.append( | 562 | installResult.append( |
| @@ -582,14 +573,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 582 | ) | 573 | ) |
| 583 | installResult.append(separator) | 574 | installResult.append(separator) |
| 584 | } | 575 | } |
| 585 | if (errorExtension > 0) { | 576 | if (error > 0) { |
| 586 | installResult.append(separator) | ||
| 587 | installResult.append( | ||
| 588 | getString(R.string.install_game_content_failure_file_extension) | ||
| 589 | ) | ||
| 590 | installResult.append(separator) | ||
| 591 | } | ||
| 592 | if (errorOther > 0) { | ||
| 593 | installResult.append( | 577 | installResult.append( |
| 594 | getString(R.string.install_game_content_failure_description) | 578 | getString(R.string.install_game_content_failure_description) |
| 595 | ) | 579 | ) |
| @@ -608,7 +592,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 608 | descriptionString = installResult.toString().trim() | 592 | descriptionString = installResult.toString().trim() |
| 609 | ) | 593 | ) |
| 610 | } | 594 | } |
| 611 | }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) | 595 | }.show(supportFragmentManager, ProgressDialogFragment.TAG) |
| 612 | } | 596 | } |
| 613 | 597 | ||
| 614 | val exportUserData = registerForActivityResult( | 598 | val exportUserData = registerForActivityResult( |
| @@ -618,16 +602,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 618 | return@registerForActivityResult | 602 | return@registerForActivityResult |
| 619 | } | 603 | } |
| 620 | 604 | ||
| 621 | IndeterminateProgressDialogFragment.newInstance( | 605 | ProgressDialogFragment.newInstance( |
| 622 | this, | 606 | this, |
| 623 | R.string.exporting_user_data, | 607 | R.string.exporting_user_data, |
| 624 | true | 608 | true |
| 625 | ) { | 609 | ) { progressCallback, _ -> |
| 626 | val zipResult = FileUtil.zipFromInternalStorage( | 610 | val zipResult = FileUtil.zipFromInternalStorage( |
| 627 | File(DirectoryInitialization.userDirectory!!), | 611 | File(DirectoryInitialization.userDirectory!!), |
| 628 | DirectoryInitialization.userDirectory!!, | 612 | DirectoryInitialization.userDirectory!!, |
| 629 | BufferedOutputStream(contentResolver.openOutputStream(result)), | 613 | BufferedOutputStream(contentResolver.openOutputStream(result)), |
| 630 | taskViewModel.cancelled, | 614 | progressCallback, |
| 631 | compression = false | 615 | compression = false |
| 632 | ) | 616 | ) |
| 633 | return@newInstance when (zipResult) { | 617 | return@newInstance when (zipResult) { |
| @@ -635,7 +619,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 635 | TaskState.Failed -> R.string.export_failed | 619 | TaskState.Failed -> R.string.export_failed |
| 636 | TaskState.Cancelled -> R.string.user_data_export_cancelled | 620 | TaskState.Cancelled -> R.string.user_data_export_cancelled |
| 637 | } | 621 | } |
| 638 | }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) | 622 | }.show(supportFragmentManager, ProgressDialogFragment.TAG) |
| 639 | } | 623 | } |
| 640 | 624 | ||
| 641 | val importUserData = | 625 | val importUserData = |
| @@ -644,10 +628,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 644 | return@registerForActivityResult | 628 | return@registerForActivityResult |
| 645 | } | 629 | } |
| 646 | 630 | ||
| 647 | IndeterminateProgressDialogFragment.newInstance( | 631 | ProgressDialogFragment.newInstance( |
| 648 | this, | 632 | this, |
| 649 | R.string.importing_user_data | 633 | R.string.importing_user_data |
| 650 | ) { | 634 | ) { progressCallback, _ -> |
| 651 | val checkStream = | 635 | val checkStream = |
| 652 | ZipInputStream(BufferedInputStream(contentResolver.openInputStream(result))) | 636 | ZipInputStream(BufferedInputStream(contentResolver.openInputStream(result))) |
| 653 | var isYuzuBackup = false | 637 | var isYuzuBackup = false |
| @@ -676,8 +660,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 676 | // Copy archive to internal storage | 660 | // Copy archive to internal storage |
| 677 | try { | 661 | try { |
| 678 | FileUtil.unzipToInternalStorage( | 662 | FileUtil.unzipToInternalStorage( |
| 679 | BufferedInputStream(contentResolver.openInputStream(result)), | 663 | result.toString(), |
| 680 | File(DirectoryInitialization.userDirectory!!) | 664 | File(DirectoryInitialization.userDirectory!!), |
| 665 | progressCallback | ||
| 681 | ) | 666 | ) |
| 682 | } catch (e: Exception) { | 667 | } catch (e: Exception) { |
| 683 | return@newInstance MessageDialogFragment.newInstance( | 668 | return@newInstance MessageDialogFragment.newInstance( |
| @@ -694,6 +679,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 694 | driverViewModel.reloadDriverData() | 679 | driverViewModel.reloadDriverData() |
| 695 | 680 | ||
| 696 | return@newInstance getString(R.string.user_data_import_success) | 681 | return@newInstance getString(R.string.user_data_import_success) |
| 697 | }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) | 682 | }.show(supportFragmentManager, ProgressDialogFragment.TAG) |
| 698 | } | 683 | } |
| 699 | } | 684 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt index b54a19c65..fc2339f5a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt | |||
| @@ -7,7 +7,6 @@ import android.database.Cursor | |||
| 7 | import android.net.Uri | 7 | import android.net.Uri |
| 8 | import android.provider.DocumentsContract | 8 | import android.provider.DocumentsContract |
| 9 | import androidx.documentfile.provider.DocumentFile | 9 | import androidx.documentfile.provider.DocumentFile |
| 10 | import kotlinx.coroutines.flow.StateFlow | ||
| 11 | import java.io.BufferedInputStream | 10 | import java.io.BufferedInputStream |
| 12 | import java.io.File | 11 | import java.io.File |
| 13 | import java.io.IOException | 12 | import java.io.IOException |
| @@ -19,6 +18,7 @@ import org.yuzu.yuzu_emu.YuzuApplication | |||
| 19 | import org.yuzu.yuzu_emu.model.MinimalDocumentFile | 18 | import org.yuzu.yuzu_emu.model.MinimalDocumentFile |
| 20 | import org.yuzu.yuzu_emu.model.TaskState | 19 | import org.yuzu.yuzu_emu.model.TaskState |
| 21 | import java.io.BufferedOutputStream | 20 | import java.io.BufferedOutputStream |
| 21 | import java.io.OutputStream | ||
| 22 | import java.lang.NullPointerException | 22 | import java.lang.NullPointerException |
| 23 | import java.nio.charset.StandardCharsets | 23 | import java.nio.charset.StandardCharsets |
| 24 | import java.util.zip.Deflater | 24 | import java.util.zip.Deflater |
| @@ -283,12 +283,34 @@ object FileUtil { | |||
| 283 | 283 | ||
| 284 | /** | 284 | /** |
| 285 | * Extracts the given zip file into the given directory. | 285 | * Extracts the given zip file into the given directory. |
| 286 | * @param path String representation of a [Uri] or a typical path delimited by '/' | ||
| 287 | * @param destDir Location to unzip the contents of [path] into | ||
| 288 | * @param progressCallback Lambda that is called with the total number of files and the current | ||
| 289 | * progress through the process. Stops execution as soon as possible if this returns true. | ||
| 286 | */ | 290 | */ |
| 287 | @Throws(SecurityException::class) | 291 | @Throws(SecurityException::class) |
| 288 | fun unzipToInternalStorage(zipStream: BufferedInputStream, destDir: File) { | 292 | fun unzipToInternalStorage( |
| 289 | ZipInputStream(zipStream).use { zis -> | 293 | path: String, |
| 294 | destDir: File, | ||
| 295 | progressCallback: (max: Long, progress: Long) -> Boolean = { _, _ -> false } | ||
| 296 | ) { | ||
| 297 | var totalEntries = 0L | ||
| 298 | ZipInputStream(getInputStream(path)).use { zis -> | ||
| 299 | var tempEntry = zis.nextEntry | ||
| 300 | while (tempEntry != null) { | ||
| 301 | tempEntry = zis.nextEntry | ||
| 302 | totalEntries++ | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | var progress = 0L | ||
| 307 | ZipInputStream(getInputStream(path)).use { zis -> | ||
| 290 | var entry: ZipEntry? = zis.nextEntry | 308 | var entry: ZipEntry? = zis.nextEntry |
| 291 | while (entry != null) { | 309 | while (entry != null) { |
| 310 | if (progressCallback.invoke(totalEntries, progress)) { | ||
| 311 | return@use | ||
| 312 | } | ||
| 313 | |||
| 292 | val newFile = File(destDir, entry.name) | 314 | val newFile = File(destDir, entry.name) |
| 293 | val destinationDirectory = if (entry.isDirectory) newFile else newFile.parentFile | 315 | val destinationDirectory = if (entry.isDirectory) newFile else newFile.parentFile |
| 294 | 316 | ||
| @@ -304,6 +326,7 @@ object FileUtil { | |||
| 304 | newFile.outputStream().use { fos -> zis.copyTo(fos) } | 326 | newFile.outputStream().use { fos -> zis.copyTo(fos) } |
| 305 | } | 327 | } |
| 306 | entry = zis.nextEntry | 328 | entry = zis.nextEntry |
| 329 | progress++ | ||
| 307 | } | 330 | } |
| 308 | } | 331 | } |
| 309 | } | 332 | } |
| @@ -313,14 +336,15 @@ object FileUtil { | |||
| 313 | * @param inputFile File representation of the item that will be zipped | 336 | * @param inputFile File representation of the item that will be zipped |
| 314 | * @param rootDir Directory containing the inputFile | 337 | * @param rootDir Directory containing the inputFile |
| 315 | * @param outputStream Stream where the zip file will be output | 338 | * @param outputStream Stream where the zip file will be output |
| 316 | * @param cancelled [StateFlow] that reports whether this process has been cancelled | 339 | * @param progressCallback Lambda that is called with the total number of files and the current |
| 340 | * progress through the process. Stops execution as soon as possible if this returns true. | ||
| 317 | * @param compression Disables compression if true | 341 | * @param compression Disables compression if true |
| 318 | */ | 342 | */ |
| 319 | fun zipFromInternalStorage( | 343 | fun zipFromInternalStorage( |
| 320 | inputFile: File, | 344 | inputFile: File, |
| 321 | rootDir: String, | 345 | rootDir: String, |
| 322 | outputStream: BufferedOutputStream, | 346 | outputStream: BufferedOutputStream, |
| 323 | cancelled: StateFlow<Boolean>? = null, | 347 | progressCallback: (max: Long, progress: Long) -> Boolean = { _, _ -> false }, |
| 324 | compression: Boolean = true | 348 | compression: Boolean = true |
| 325 | ): TaskState { | 349 | ): TaskState { |
| 326 | try { | 350 | try { |
| @@ -330,8 +354,10 @@ object FileUtil { | |||
| 330 | zos.setLevel(Deflater.NO_COMPRESSION) | 354 | zos.setLevel(Deflater.NO_COMPRESSION) |
| 331 | } | 355 | } |
| 332 | 356 | ||
| 357 | var count = 0L | ||
| 358 | val totalFiles = inputFile.walkTopDown().count().toLong() | ||
| 333 | inputFile.walkTopDown().forEach { file -> | 359 | inputFile.walkTopDown().forEach { file -> |
| 334 | if (cancelled?.value == true) { | 360 | if (progressCallback.invoke(totalFiles, count)) { |
| 335 | return TaskState.Cancelled | 361 | return TaskState.Cancelled |
| 336 | } | 362 | } |
| 337 | 363 | ||
| @@ -343,6 +369,7 @@ object FileUtil { | |||
| 343 | if (file.isFile) { | 369 | if (file.isFile) { |
| 344 | file.inputStream().use { fis -> fis.copyTo(zos) } | 370 | file.inputStream().use { fis -> fis.copyTo(zos) } |
| 345 | } | 371 | } |
| 372 | count++ | ||
| 346 | } | 373 | } |
| 347 | } | 374 | } |
| 348 | } | 375 | } |
| @@ -356,9 +383,14 @@ object FileUtil { | |||
| 356 | /** | 383 | /** |
| 357 | * Helper function that copies the contents of a DocumentFile folder into a [File] | 384 | * Helper function that copies the contents of a DocumentFile folder into a [File] |
| 358 | * @param file [File] representation of the folder to copy into | 385 | * @param file [File] representation of the folder to copy into |
| 386 | * @param progressCallback Lambda that is called with the total number of files and the current | ||
| 387 | * progress through the process. Stops execution as soon as possible if this returns true. | ||
| 359 | * @throws IllegalStateException Fails when trying to copy a folder into a file and vice versa | 388 | * @throws IllegalStateException Fails when trying to copy a folder into a file and vice versa |
| 360 | */ | 389 | */ |
| 361 | fun DocumentFile.copyFilesTo(file: File) { | 390 | fun DocumentFile.copyFilesTo( |
| 391 | file: File, | ||
| 392 | progressCallback: (max: Long, progress: Long) -> Boolean = { _, _ -> false } | ||
| 393 | ) { | ||
| 362 | file.mkdirs() | 394 | file.mkdirs() |
| 363 | if (!this.isDirectory || !file.isDirectory) { | 395 | if (!this.isDirectory || !file.isDirectory) { |
| 364 | throw IllegalStateException( | 396 | throw IllegalStateException( |
| @@ -366,7 +398,13 @@ object FileUtil { | |||
| 366 | ) | 398 | ) |
| 367 | } | 399 | } |
| 368 | 400 | ||
| 401 | var count = 0L | ||
| 402 | val totalFiles = this.listFiles().size.toLong() | ||
| 369 | this.listFiles().forEach { | 403 | this.listFiles().forEach { |
| 404 | if (progressCallback.invoke(totalFiles, count)) { | ||
| 405 | return | ||
| 406 | } | ||
| 407 | |||
| 370 | val newFile = File(file, it.name!!) | 408 | val newFile = File(file, it.name!!) |
| 371 | if (it.isDirectory) { | 409 | if (it.isDirectory) { |
| 372 | newFile.mkdirs() | 410 | newFile.mkdirs() |
| @@ -381,6 +419,7 @@ object FileUtil { | |||
| 381 | newFile.outputStream().use { os -> bos.copyTo(os) } | 419 | newFile.outputStream().use { os -> bos.copyTo(os) } |
| 382 | } | 420 | } |
| 383 | } | 421 | } |
| 422 | count++ | ||
| 384 | } | 423 | } |
| 385 | } | 424 | } |
| 386 | 425 | ||
| @@ -427,6 +466,18 @@ object FileUtil { | |||
| 427 | } | 466 | } |
| 428 | } | 467 | } |
| 429 | 468 | ||
| 469 | fun getInputStream(path: String) = if (path.contains("content://")) { | ||
| 470 | Uri.parse(path).inputStream() | ||
| 471 | } else { | ||
| 472 | File(path).inputStream() | ||
| 473 | } | ||
| 474 | |||
| 475 | fun getOutputStream(path: String) = if (path.contains("content://")) { | ||
| 476 | Uri.parse(path).outputStream() | ||
| 477 | } else { | ||
| 478 | File(path).outputStream() | ||
| 479 | } | ||
| 480 | |||
| 430 | @Throws(IOException::class) | 481 | @Throws(IOException::class) |
| 431 | fun getStringFromFile(file: File): String = | 482 | fun getStringFromFile(file: File): String = |
| 432 | String(file.readBytes(), StandardCharsets.UTF_8) | 483 | String(file.readBytes(), StandardCharsets.UTF_8) |
| @@ -434,4 +485,19 @@ object FileUtil { | |||
| 434 | @Throws(IOException::class) | 485 | @Throws(IOException::class) |
| 435 | fun getStringFromInputStream(stream: InputStream): String = | 486 | fun getStringFromInputStream(stream: InputStream): String = |
| 436 | String(stream.readBytes(), StandardCharsets.UTF_8) | 487 | String(stream.readBytes(), StandardCharsets.UTF_8) |
| 488 | |||
| 489 | fun DocumentFile.inputStream(): InputStream = | ||
| 490 | YuzuApplication.appContext.contentResolver.openInputStream(uri)!! | ||
| 491 | |||
| 492 | fun DocumentFile.outputStream(): OutputStream = | ||
| 493 | YuzuApplication.appContext.contentResolver.openOutputStream(uri)!! | ||
| 494 | |||
| 495 | fun Uri.inputStream(): InputStream = | ||
| 496 | YuzuApplication.appContext.contentResolver.openInputStream(this)!! | ||
| 497 | |||
| 498 | fun Uri.outputStream(): OutputStream = | ||
| 499 | YuzuApplication.appContext.contentResolver.openOutputStream(this)!! | ||
| 500 | |||
| 501 | fun Uri.asDocumentFile(): DocumentFile? = | ||
| 502 | DocumentFile.fromSingleUri(YuzuApplication.appContext, this) | ||
| 437 | } | 503 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt index a8f9dcc34..81212cbee 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt | |||
| @@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.utils | |||
| 5 | 5 | ||
| 6 | import android.net.Uri | 6 | import android.net.Uri |
| 7 | import android.os.Build | 7 | import android.os.Build |
| 8 | import java.io.BufferedInputStream | ||
| 9 | import java.io.File | 8 | import java.io.File |
| 10 | import java.io.IOException | 9 | import java.io.IOException |
| 11 | import org.yuzu.yuzu_emu.NativeLibrary | 10 | import org.yuzu.yuzu_emu.NativeLibrary |
| @@ -123,7 +122,7 @@ object GpuDriverHelper { | |||
| 123 | // Unzip the driver. | 122 | // Unzip the driver. |
| 124 | try { | 123 | try { |
| 125 | FileUtil.unzipToInternalStorage( | 124 | FileUtil.unzipToInternalStorage( |
| 126 | BufferedInputStream(copiedFile.inputStream()), | 125 | copiedFile.path, |
| 127 | File(driverInstallationPath!!) | 126 | File(driverInstallationPath!!) |
| 128 | ) | 127 | ) |
| 129 | } catch (e: SecurityException) { | 128 | } catch (e: SecurityException) { |
| @@ -156,7 +155,7 @@ object GpuDriverHelper { | |||
| 156 | // Unzip the driver to the private installation directory | 155 | // Unzip the driver to the private installation directory |
| 157 | try { | 156 | try { |
| 158 | FileUtil.unzipToInternalStorage( | 157 | FileUtil.unzipToInternalStorage( |
| 159 | BufferedInputStream(driver.inputStream()), | 158 | driver.path, |
| 160 | File(driverInstallationPath!!) | 159 | File(driverInstallationPath!!) |
| 161 | ) | 160 | ) |
| 162 | } catch (e: SecurityException) { | 161 | } catch (e: SecurityException) { |
diff --git a/src/android/app/src/main/jni/android_common/android_common.cpp b/src/android/app/src/main/jni/android_common/android_common.cpp index 1e884ffdd..7018a52af 100644 --- a/src/android/app/src/main/jni/android_common/android_common.cpp +++ b/src/android/app/src/main/jni/android_common/android_common.cpp | |||
| @@ -42,3 +42,19 @@ double GetJDouble(JNIEnv* env, jobject jdouble) { | |||
| 42 | jobject ToJDouble(JNIEnv* env, double value) { | 42 | jobject ToJDouble(JNIEnv* env, double value) { |
| 43 | return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value); | 43 | return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value); |
| 44 | } | 44 | } |
| 45 | |||
| 46 | s32 GetJInteger(JNIEnv* env, jobject jinteger) { | ||
| 47 | return env->GetIntField(jinteger, IDCache::GetIntegerValueField()); | ||
| 48 | } | ||
| 49 | |||
| 50 | jobject ToJInteger(JNIEnv* env, s32 value) { | ||
| 51 | return env->NewObject(IDCache::GetIntegerClass(), IDCache::GetIntegerConstructor(), value); | ||
| 52 | } | ||
| 53 | |||
| 54 | bool GetJBoolean(JNIEnv* env, jobject jboolean) { | ||
| 55 | return env->GetBooleanField(jboolean, IDCache::GetBooleanValueField()); | ||
| 56 | } | ||
| 57 | |||
| 58 | jobject ToJBoolean(JNIEnv* env, bool value) { | ||
| 59 | return env->NewObject(IDCache::GetBooleanClass(), IDCache::GetBooleanConstructor(), value); | ||
| 60 | } | ||
diff --git a/src/android/app/src/main/jni/android_common/android_common.h b/src/android/app/src/main/jni/android_common/android_common.h index 8eb803e1b..29a338c0a 100644 --- a/src/android/app/src/main/jni/android_common/android_common.h +++ b/src/android/app/src/main/jni/android_common/android_common.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <string> | 6 | #include <string> |
| 7 | 7 | ||
| 8 | #include <jni.h> | 8 | #include <jni.h> |
| 9 | #include "common/common_types.h" | ||
| 9 | 10 | ||
| 10 | std::string GetJString(JNIEnv* env, jstring jstr); | 11 | std::string GetJString(JNIEnv* env, jstring jstr); |
| 11 | jstring ToJString(JNIEnv* env, std::string_view str); | 12 | jstring ToJString(JNIEnv* env, std::string_view str); |
| @@ -13,3 +14,9 @@ jstring ToJString(JNIEnv* env, std::u16string_view str); | |||
| 13 | 14 | ||
| 14 | double GetJDouble(JNIEnv* env, jobject jdouble); | 15 | double GetJDouble(JNIEnv* env, jobject jdouble); |
| 15 | jobject ToJDouble(JNIEnv* env, double value); | 16 | jobject ToJDouble(JNIEnv* env, double value); |
| 17 | |||
| 18 | s32 GetJInteger(JNIEnv* env, jobject jinteger); | ||
| 19 | jobject ToJInteger(JNIEnv* env, s32 value); | ||
| 20 | |||
| 21 | bool GetJBoolean(JNIEnv* env, jobject jboolean); | ||
| 22 | jobject ToJBoolean(JNIEnv* env, bool value); | ||
diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp index 08aed3216..e147560c3 100644 --- a/src/android/app/src/main/jni/android_config.cpp +++ b/src/android/app/src/main/jni/android_config.cpp | |||
| @@ -21,7 +21,7 @@ void AndroidConfig::ReloadAllValues() { | |||
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | void AndroidConfig::SaveAllValues() { | 23 | void AndroidConfig::SaveAllValues() { |
| 24 | Save(); | 24 | SaveValues(); |
| 25 | SaveAndroidValues(); | 25 | SaveAndroidValues(); |
| 26 | } | 26 | } |
| 27 | 27 | ||
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp index c79ad7d76..96f2ad3d4 100644 --- a/src/android/app/src/main/jni/id_cache.cpp +++ b/src/android/app/src/main/jni/id_cache.cpp | |||
| @@ -43,10 +43,27 @@ static jfieldID s_overlay_control_data_landscape_position_field; | |||
| 43 | static jfieldID s_overlay_control_data_portrait_position_field; | 43 | static jfieldID s_overlay_control_data_portrait_position_field; |
| 44 | static jfieldID s_overlay_control_data_foldable_position_field; | 44 | static jfieldID s_overlay_control_data_foldable_position_field; |
| 45 | 45 | ||
| 46 | static jclass s_patch_class; | ||
| 47 | static jmethodID s_patch_constructor; | ||
| 48 | static jfieldID s_patch_enabled_field; | ||
| 49 | static jfieldID s_patch_name_field; | ||
| 50 | static jfieldID s_patch_version_field; | ||
| 51 | static jfieldID s_patch_type_field; | ||
| 52 | static jfieldID s_patch_program_id_field; | ||
| 53 | static jfieldID s_patch_title_id_field; | ||
| 54 | |||
| 46 | static jclass s_double_class; | 55 | static jclass s_double_class; |
| 47 | static jmethodID s_double_constructor; | 56 | static jmethodID s_double_constructor; |
| 48 | static jfieldID s_double_value_field; | 57 | static jfieldID s_double_value_field; |
| 49 | 58 | ||
| 59 | static jclass s_integer_class; | ||
| 60 | static jmethodID s_integer_constructor; | ||
| 61 | static jfieldID s_integer_value_field; | ||
| 62 | |||
| 63 | static jclass s_boolean_class; | ||
| 64 | static jmethodID s_boolean_constructor; | ||
| 65 | static jfieldID s_boolean_value_field; | ||
| 66 | |||
| 50 | static constexpr jint JNI_VERSION = JNI_VERSION_1_6; | 67 | static constexpr jint JNI_VERSION = JNI_VERSION_1_6; |
| 51 | 68 | ||
| 52 | namespace IDCache { | 69 | namespace IDCache { |
| @@ -186,6 +203,38 @@ jfieldID GetOverlayControlDataFoldablePositionField() { | |||
| 186 | return s_overlay_control_data_foldable_position_field; | 203 | return s_overlay_control_data_foldable_position_field; |
| 187 | } | 204 | } |
| 188 | 205 | ||
| 206 | jclass GetPatchClass() { | ||
| 207 | return s_patch_class; | ||
| 208 | } | ||
| 209 | |||
| 210 | jmethodID GetPatchConstructor() { | ||
| 211 | return s_patch_constructor; | ||
| 212 | } | ||
| 213 | |||
| 214 | jfieldID GetPatchEnabledField() { | ||
| 215 | return s_patch_enabled_field; | ||
| 216 | } | ||
| 217 | |||
| 218 | jfieldID GetPatchNameField() { | ||
| 219 | return s_patch_name_field; | ||
| 220 | } | ||
| 221 | |||
| 222 | jfieldID GetPatchVersionField() { | ||
| 223 | return s_patch_version_field; | ||
| 224 | } | ||
| 225 | |||
| 226 | jfieldID GetPatchTypeField() { | ||
| 227 | return s_patch_type_field; | ||
| 228 | } | ||
| 229 | |||
| 230 | jfieldID GetPatchProgramIdField() { | ||
| 231 | return s_patch_program_id_field; | ||
| 232 | } | ||
| 233 | |||
| 234 | jfieldID GetPatchTitleIdField() { | ||
| 235 | return s_patch_title_id_field; | ||
| 236 | } | ||
| 237 | |||
| 189 | jclass GetDoubleClass() { | 238 | jclass GetDoubleClass() { |
| 190 | return s_double_class; | 239 | return s_double_class; |
| 191 | } | 240 | } |
| @@ -198,6 +247,30 @@ jfieldID GetDoubleValueField() { | |||
| 198 | return s_double_value_field; | 247 | return s_double_value_field; |
| 199 | } | 248 | } |
| 200 | 249 | ||
| 250 | jclass GetIntegerClass() { | ||
| 251 | return s_integer_class; | ||
| 252 | } | ||
| 253 | |||
| 254 | jmethodID GetIntegerConstructor() { | ||
| 255 | return s_integer_constructor; | ||
| 256 | } | ||
| 257 | |||
| 258 | jfieldID GetIntegerValueField() { | ||
| 259 | return s_integer_value_field; | ||
| 260 | } | ||
| 261 | |||
| 262 | jclass GetBooleanClass() { | ||
| 263 | return s_boolean_class; | ||
| 264 | } | ||
| 265 | |||
| 266 | jmethodID GetBooleanConstructor() { | ||
| 267 | return s_boolean_constructor; | ||
| 268 | } | ||
| 269 | |||
| 270 | jfieldID GetBooleanValueField() { | ||
| 271 | return s_boolean_value_field; | ||
| 272 | } | ||
| 273 | |||
| 201 | } // namespace IDCache | 274 | } // namespace IDCache |
| 202 | 275 | ||
| 203 | #ifdef __cplusplus | 276 | #ifdef __cplusplus |
| @@ -278,12 +351,37 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { | |||
| 278 | env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;"); | 351 | env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;"); |
| 279 | env->DeleteLocalRef(overlay_control_data_class); | 352 | env->DeleteLocalRef(overlay_control_data_class); |
| 280 | 353 | ||
| 354 | const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch"); | ||
| 355 | s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class)); | ||
| 356 | s_patch_constructor = env->GetMethodID( | ||
| 357 | patch_class, "<init>", | ||
| 358 | "(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V"); | ||
| 359 | s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z"); | ||
| 360 | s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;"); | ||
| 361 | s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;"); | ||
| 362 | s_patch_type_field = env->GetFieldID(patch_class, "type", "I"); | ||
| 363 | s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;"); | ||
| 364 | s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;"); | ||
| 365 | env->DeleteLocalRef(patch_class); | ||
| 366 | |||
| 281 | const jclass double_class = env->FindClass("java/lang/Double"); | 367 | const jclass double_class = env->FindClass("java/lang/Double"); |
| 282 | s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class)); | 368 | s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class)); |
| 283 | s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V"); | 369 | s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V"); |
| 284 | s_double_value_field = env->GetFieldID(double_class, "value", "D"); | 370 | s_double_value_field = env->GetFieldID(double_class, "value", "D"); |
| 285 | env->DeleteLocalRef(double_class); | 371 | env->DeleteLocalRef(double_class); |
| 286 | 372 | ||
| 373 | const jclass int_class = env->FindClass("java/lang/Integer"); | ||
| 374 | s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class)); | ||
| 375 | s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V"); | ||
| 376 | s_integer_value_field = env->GetFieldID(int_class, "value", "I"); | ||
| 377 | env->DeleteLocalRef(int_class); | ||
| 378 | |||
| 379 | const jclass boolean_class = env->FindClass("java/lang/Boolean"); | ||
| 380 | s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class)); | ||
| 381 | s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V"); | ||
| 382 | s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z"); | ||
| 383 | env->DeleteLocalRef(boolean_class); | ||
| 384 | |||
| 287 | // Initialize Android Storage | 385 | // Initialize Android Storage |
| 288 | Common::FS::Android::RegisterCallbacks(env, s_native_library_class); | 386 | Common::FS::Android::RegisterCallbacks(env, s_native_library_class); |
| 289 | 387 | ||
| @@ -309,7 +407,10 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) { | |||
| 309 | env->DeleteGlobalRef(s_string_class); | 407 | env->DeleteGlobalRef(s_string_class); |
| 310 | env->DeleteGlobalRef(s_pair_class); | 408 | env->DeleteGlobalRef(s_pair_class); |
| 311 | env->DeleteGlobalRef(s_overlay_control_data_class); | 409 | env->DeleteGlobalRef(s_overlay_control_data_class); |
| 410 | env->DeleteGlobalRef(s_patch_class); | ||
| 312 | env->DeleteGlobalRef(s_double_class); | 411 | env->DeleteGlobalRef(s_double_class); |
| 412 | env->DeleteGlobalRef(s_integer_class); | ||
| 413 | env->DeleteGlobalRef(s_boolean_class); | ||
| 313 | 414 | ||
| 314 | // UnInitialize applets | 415 | // UnInitialize applets |
| 315 | SoftwareKeyboard::CleanupJNI(env); | 416 | SoftwareKeyboard::CleanupJNI(env); |
diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h index 784d1412f..a002e705d 100644 --- a/src/android/app/src/main/jni/id_cache.h +++ b/src/android/app/src/main/jni/id_cache.h | |||
| @@ -43,8 +43,25 @@ jfieldID GetOverlayControlDataLandscapePositionField(); | |||
| 43 | jfieldID GetOverlayControlDataPortraitPositionField(); | 43 | jfieldID GetOverlayControlDataPortraitPositionField(); |
| 44 | jfieldID GetOverlayControlDataFoldablePositionField(); | 44 | jfieldID GetOverlayControlDataFoldablePositionField(); |
| 45 | 45 | ||
| 46 | jclass GetPatchClass(); | ||
| 47 | jmethodID GetPatchConstructor(); | ||
| 48 | jfieldID GetPatchEnabledField(); | ||
| 49 | jfieldID GetPatchNameField(); | ||
| 50 | jfieldID GetPatchVersionField(); | ||
| 51 | jfieldID GetPatchTypeField(); | ||
| 52 | jfieldID GetPatchProgramIdField(); | ||
| 53 | jfieldID GetPatchTitleIdField(); | ||
| 54 | |||
| 46 | jclass GetDoubleClass(); | 55 | jclass GetDoubleClass(); |
| 47 | jmethodID GetDoubleConstructor(); | 56 | jmethodID GetDoubleConstructor(); |
| 48 | jfieldID GetDoubleValueField(); | 57 | jfieldID GetDoubleValueField(); |
| 49 | 58 | ||
| 59 | jclass GetIntegerClass(); | ||
| 60 | jmethodID GetIntegerConstructor(); | ||
| 61 | jfieldID GetIntegerValueField(); | ||
| 62 | |||
| 63 | jclass GetBooleanClass(); | ||
| 64 | jmethodID GetBooleanConstructor(); | ||
| 65 | jfieldID GetBooleanValueField(); | ||
| 66 | |||
| 50 | } // namespace IDCache | 67 | } // namespace IDCache |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index ed3b1353a..be0a723b1 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <core/file_sys/patch_manager.h> | 17 | #include <core/file_sys/patch_manager.h> |
| 18 | #include <core/file_sys/savedata_factory.h> | 18 | #include <core/file_sys/savedata_factory.h> |
| 19 | #include <core/loader/nro.h> | 19 | #include <core/loader/nro.h> |
| 20 | #include <frontend_common/content_manager.h> | ||
| 20 | #include <jni.h> | 21 | #include <jni.h> |
| 21 | 22 | ||
| 22 | #include "common/detached_tasks.h" | 23 | #include "common/detached_tasks.h" |
| @@ -100,67 +101,6 @@ void EmulationSession::SetNativeWindow(ANativeWindow* native_window) { | |||
| 100 | m_native_window = native_window; | 101 | m_native_window = native_window; |
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | int EmulationSession::InstallFileToNand(std::string filename, std::string file_extension) { | ||
| 104 | jconst copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, | ||
| 105 | std::size_t block_size) { | ||
| 106 | if (src == nullptr || dest == nullptr) { | ||
| 107 | return false; | ||
| 108 | } | ||
| 109 | if (!dest->Resize(src->GetSize())) { | ||
| 110 | return false; | ||
| 111 | } | ||
| 112 | |||
| 113 | using namespace Common::Literals; | ||
| 114 | [[maybe_unused]] std::vector<u8> buffer(1_MiB); | ||
| 115 | |||
| 116 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { | ||
| 117 | jconst read = src->Read(buffer.data(), buffer.size(), i); | ||
| 118 | dest->Write(buffer.data(), read, i); | ||
| 119 | } | ||
| 120 | return true; | ||
| 121 | }; | ||
| 122 | |||
| 123 | enum InstallResult { | ||
| 124 | Success = 0, | ||
| 125 | SuccessFileOverwritten = 1, | ||
| 126 | InstallError = 2, | ||
| 127 | ErrorBaseGame = 3, | ||
| 128 | ErrorFilenameExtension = 4, | ||
| 129 | }; | ||
| 130 | |||
| 131 | [[maybe_unused]] std::shared_ptr<FileSys::NSP> nsp; | ||
| 132 | if (file_extension == "nsp") { | ||
| 133 | nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read)); | ||
| 134 | if (nsp->IsExtractedType()) { | ||
| 135 | return InstallError; | ||
| 136 | } | ||
| 137 | } else { | ||
| 138 | return ErrorFilenameExtension; | ||
| 139 | } | ||
| 140 | |||
| 141 | if (!nsp) { | ||
| 142 | return InstallError; | ||
| 143 | } | ||
| 144 | |||
| 145 | if (nsp->GetStatus() != Loader::ResultStatus::Success) { | ||
| 146 | return InstallError; | ||
| 147 | } | ||
| 148 | |||
| 149 | jconst res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true, | ||
| 150 | copy_func); | ||
| 151 | |||
| 152 | switch (res) { | ||
| 153 | case FileSys::InstallResult::Success: | ||
| 154 | return Success; | ||
| 155 | case FileSys::InstallResult::OverwriteExisting: | ||
| 156 | return SuccessFileOverwritten; | ||
| 157 | case FileSys::InstallResult::ErrorBaseInstall: | ||
| 158 | return ErrorBaseGame; | ||
| 159 | default: | ||
| 160 | return InstallError; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | void EmulationSession::InitializeGpuDriver(const std::string& hook_lib_dir, | 104 | void EmulationSession::InitializeGpuDriver(const std::string& hook_lib_dir, |
| 165 | const std::string& custom_driver_dir, | 105 | const std::string& custom_driver_dir, |
| 166 | const std::string& custom_driver_name, | 106 | const std::string& custom_driver_name, |
| @@ -512,10 +452,20 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject | |||
| 512 | } | 452 | } |
| 513 | 453 | ||
| 514 | int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance, | 454 | int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance, |
| 515 | jstring j_file, | 455 | jstring j_file, jobject jcallback) { |
| 516 | jstring j_file_extension) { | 456 | auto jlambdaClass = env->GetObjectClass(jcallback); |
| 517 | return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file), | 457 | auto jlambdaInvokeMethod = env->GetMethodID( |
| 518 | GetJString(env, j_file_extension)); | 458 | jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); |
| 459 | const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) { | ||
| 460 | auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod, | ||
| 461 | ToJDouble(env, max), ToJDouble(env, progress)); | ||
| 462 | return GetJBoolean(env, jwasCancelled); | ||
| 463 | }; | ||
| 464 | |||
| 465 | return static_cast<int>( | ||
| 466 | ContentManager::InstallNSP(&EmulationSession::GetInstance().System(), | ||
| 467 | EmulationSession::GetInstance().System().GetFilesystem().get(), | ||
| 468 | GetJString(env, j_file), callback)); | ||
| 519 | } | 469 | } |
| 520 | 470 | ||
| 521 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj, | 471 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj, |
| @@ -824,9 +774,9 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env, | |||
| 824 | return true; | 774 | return true; |
| 825 | } | 775 | } |
| 826 | 776 | ||
| 827 | jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env, jobject jobj, | 777 | jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj, |
| 828 | jstring jpath, | 778 | jstring jpath, |
| 829 | jstring jprogramId) { | 779 | jstring jprogramId) { |
| 830 | const auto path = GetJString(env, jpath); | 780 | const auto path = GetJString(env, jpath); |
| 831 | const auto vFile = | 781 | const auto vFile = |
| 832 | Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path); | 782 | Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path); |
| @@ -843,20 +793,40 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env, | |||
| 843 | FileSys::VirtualFile update_raw; | 793 | FileSys::VirtualFile update_raw; |
| 844 | loader->ReadUpdateRaw(update_raw); | 794 | loader->ReadUpdateRaw(update_raw); |
| 845 | 795 | ||
| 846 | auto addons = pm.GetPatchVersionNames(update_raw); | 796 | auto patches = pm.GetPatches(update_raw); |
| 847 | auto jemptyString = ToJString(env, ""); | 797 | jobjectArray jpatchArray = |
| 848 | auto jemptyStringPair = env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), | 798 | env->NewObjectArray(patches.size(), IDCache::GetPatchClass(), nullptr); |
| 849 | jemptyString, jemptyString); | ||
| 850 | jobjectArray jaddonsArray = | ||
| 851 | env->NewObjectArray(addons.size(), IDCache::GetPairClass(), jemptyStringPair); | ||
| 852 | int i = 0; | 799 | int i = 0; |
| 853 | for (const auto& addon : addons) { | 800 | for (const auto& patch : patches) { |
| 854 | jobject jaddon = env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), | 801 | jobject jpatch = env->NewObject( |
| 855 | ToJString(env, addon.first), ToJString(env, addon.second)); | 802 | IDCache::GetPatchClass(), IDCache::GetPatchConstructor(), patch.enabled, |
| 856 | env->SetObjectArrayElement(jaddonsArray, i, jaddon); | 803 | ToJString(env, patch.name), ToJString(env, patch.version), |
| 804 | static_cast<jint>(patch.type), ToJString(env, std::to_string(patch.program_id)), | ||
| 805 | ToJString(env, std::to_string(patch.title_id))); | ||
| 806 | env->SetObjectArrayElement(jpatchArray, i, jpatch); | ||
| 857 | ++i; | 807 | ++i; |
| 858 | } | 808 | } |
| 859 | return jaddonsArray; | 809 | return jpatchArray; |
| 810 | } | ||
| 811 | |||
| 812 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject jobj, | ||
| 813 | jstring jprogramId) { | ||
| 814 | auto program_id = EmulationSession::GetProgramId(env, jprogramId); | ||
| 815 | ContentManager::RemoveUpdate(EmulationSession::GetInstance().System().GetFileSystemController(), | ||
| 816 | program_id); | ||
| 817 | } | ||
| 818 | |||
| 819 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj, | ||
| 820 | jstring jprogramId) { | ||
| 821 | auto program_id = EmulationSession::GetProgramId(env, jprogramId); | ||
| 822 | ContentManager::RemoveAllDLC(&EmulationSession::GetInstance().System(), program_id); | ||
| 823 | } | ||
| 824 | |||
| 825 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId, | ||
| 826 | jstring jname) { | ||
| 827 | auto program_id = EmulationSession::GetProgramId(env, jprogramId); | ||
| 828 | ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(), | ||
| 829 | program_id, GetJString(env, jname)); | ||
| 860 | } | 830 | } |
| 861 | 831 | ||
| 862 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, | 832 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, |
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h index 4a8049578..dadb138ad 100644 --- a/src/android/app/src/main/jni/native.h +++ b/src/android/app/src/main/jni/native.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "core/file_sys/registered_cache.h" | 7 | #include "core/file_sys/registered_cache.h" |
| 8 | #include "core/hle/service/acc/profile_manager.h" | 8 | #include "core/hle/service/acc/profile_manager.h" |
| 9 | #include "core/perf_stats.h" | 9 | #include "core/perf_stats.h" |
| 10 | #include "frontend_common/content_manager.h" | ||
| 10 | #include "jni/applets/software_keyboard.h" | 11 | #include "jni/applets/software_keyboard.h" |
| 11 | #include "jni/emu_window/emu_window.h" | 12 | #include "jni/emu_window/emu_window.h" |
| 12 | #include "video_core/rasterizer_interface.h" | 13 | #include "video_core/rasterizer_interface.h" |
| @@ -29,7 +30,6 @@ public: | |||
| 29 | void SetNativeWindow(ANativeWindow* native_window); | 30 | void SetNativeWindow(ANativeWindow* native_window); |
| 30 | void SurfaceChanged(); | 31 | void SurfaceChanged(); |
| 31 | 32 | ||
| 32 | int InstallFileToNand(std::string filename, std::string file_extension); | ||
| 33 | void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir, | 33 | void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir, |
| 34 | const std::string& custom_driver_name, | 34 | const std::string& custom_driver_name, |
| 35 | const std::string& file_redirect_dir); | 35 | const std::string& file_redirect_dir); |
diff --git a/src/android/app/src/main/res/layout/card_home_option.xml b/src/android/app/src/main/res/layout/card_home_option.xml index cb667c928..224ec4d89 100644 --- a/src/android/app/src/main/res/layout/card_home_option.xml +++ b/src/android/app/src/main/res/layout/card_home_option.xml | |||
| @@ -2,16 +2,16 @@ | |||
| 2 | <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" | 2 | <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | xmlns:app="http://schemas.android.com/apk/res-auto" | 3 | xmlns:app="http://schemas.android.com/apk/res-auto" |
| 4 | xmlns:tools="http://schemas.android.com/tools" | 4 | xmlns:tools="http://schemas.android.com/tools" |
| 5 | style="?attr/materialCardViewFilledStyle" | 5 | style="?attr/materialCardViewElevatedStyle" |
| 6 | android:id="@+id/option_card" | 6 | android:id="@+id/option_card" |
| 7 | android:layout_width="match_parent" | 7 | android:layout_width="match_parent" |
| 8 | android:layout_height="wrap_content" | 8 | android:layout_height="wrap_content" |
| 9 | android:layout_marginBottom="24dp" | 9 | android:layout_marginBottom="24dp" |
| 10 | android:layout_marginHorizontal="12dp" | 10 | android:layout_marginHorizontal="12dp" |
| 11 | android:background="?attr/selectableItemBackground" | 11 | android:background="?attr/selectableItemBackground" |
| 12 | android:backgroundTint="?attr/colorSurfaceVariant" | ||
| 13 | android:clickable="true" | 12 | android:clickable="true" |
| 14 | android:focusable="true"> | 13 | android:focusable="true" |
| 14 | app:cardElevation="4dp"> | ||
| 15 | 15 | ||
| 16 | <LinearLayout | 16 | <LinearLayout |
| 17 | android:id="@+id/option_layout" | 17 | android:id="@+id/option_layout" |
diff --git a/src/android/app/src/main/res/layout/dialog_progress_bar.xml b/src/android/app/src/main/res/layout/dialog_progress_bar.xml index 0209ea082..e61aa5294 100644 --- a/src/android/app/src/main/res/layout/dialog_progress_bar.xml +++ b/src/android/app/src/main/res/layout/dialog_progress_bar.xml | |||
| @@ -1,8 +1,30 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | 1 | <?xml version="1.0" encoding="utf-8"?> |
| 2 | <com.google.android.material.progressindicator.LinearProgressIndicator xmlns:android="http://schemas.android.com/apk/res/android" | 2 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | xmlns:app="http://schemas.android.com/apk/res-auto" | 3 | xmlns:app="http://schemas.android.com/apk/res-auto" |
| 4 | android:id="@+id/progress_bar" | ||
| 5 | android:layout_width="match_parent" | 4 | android:layout_width="match_parent" |
| 6 | android:layout_height="wrap_content" | 5 | android:layout_height="wrap_content" |
| 7 | android:padding="24dp" | 6 | android:orientation="vertical"> |
| 8 | app:trackCornerRadius="4dp" /> | 7 | |
| 8 | <com.google.android.material.textview.MaterialTextView | ||
| 9 | android:id="@+id/message" | ||
| 10 | style="@style/TextAppearance.Material3.BodyMedium" | ||
| 11 | android:layout_width="match_parent" | ||
| 12 | android:layout_height="wrap_content" | ||
| 13 | android:layout_marginHorizontal="24dp" | ||
| 14 | android:layout_marginTop="12dp" | ||
| 15 | android:layout_marginBottom="6dp" | ||
| 16 | android:ellipsize="marquee" | ||
| 17 | android:marqueeRepeatLimit="marquee_forever" | ||
| 18 | android:requiresFadingEdge="horizontal" | ||
| 19 | android:singleLine="true" | ||
| 20 | android:textAlignment="viewStart" | ||
| 21 | android:visibility="gone" /> | ||
| 22 | |||
| 23 | <com.google.android.material.progressindicator.LinearProgressIndicator | ||
| 24 | android:id="@+id/progress_bar" | ||
| 25 | android:layout_width="match_parent" | ||
| 26 | android:layout_height="wrap_content" | ||
| 27 | android:padding="24dp" | ||
| 28 | app:trackCornerRadius="4dp" /> | ||
| 29 | |||
| 30 | </LinearLayout> | ||
diff --git a/src/android/app/src/main/res/layout/list_item_addon.xml b/src/android/app/src/main/res/layout/list_item_addon.xml index 74ca04ef1..3a1382fe2 100644 --- a/src/android/app/src/main/res/layout/list_item_addon.xml +++ b/src/android/app/src/main/res/layout/list_item_addon.xml | |||
| @@ -14,12 +14,11 @@ | |||
| 14 | android:id="@+id/text_container" | 14 | android:id="@+id/text_container" |
| 15 | android:layout_width="0dp" | 15 | android:layout_width="0dp" |
| 16 | android:layout_height="wrap_content" | 16 | android:layout_height="wrap_content" |
| 17 | android:layout_marginEnd="16dp" | ||
| 18 | android:orientation="vertical" | 17 | android:orientation="vertical" |
| 19 | app:layout_constraintBottom_toBottomOf="@+id/addon_switch" | 18 | android:layout_marginEnd="16dp" |
| 20 | app:layout_constraintEnd_toStartOf="@+id/addon_switch" | 19 | app:layout_constraintEnd_toStartOf="@+id/addon_checkbox" |
| 21 | app:layout_constraintStart_toStartOf="parent" | 20 | app:layout_constraintStart_toStartOf="parent" |
| 22 | app:layout_constraintTop_toTopOf="@+id/addon_switch"> | 21 | app:layout_constraintTop_toTopOf="parent"> |
| 23 | 22 | ||
| 24 | <com.google.android.material.textview.MaterialTextView | 23 | <com.google.android.material.textview.MaterialTextView |
| 25 | android:id="@+id/title" | 24 | android:id="@+id/title" |
| @@ -42,16 +41,29 @@ | |||
| 42 | 41 | ||
| 43 | </LinearLayout> | 42 | </LinearLayout> |
| 44 | 43 | ||
| 45 | <com.google.android.material.materialswitch.MaterialSwitch | 44 | <com.google.android.material.checkbox.MaterialCheckBox |
| 46 | android:id="@+id/addon_switch" | 45 | android:id="@+id/addon_checkbox" |
| 47 | android:layout_width="wrap_content" | 46 | android:layout_width="wrap_content" |
| 48 | android:layout_height="wrap_content" | 47 | android:layout_height="wrap_content" |
| 49 | android:focusable="true" | 48 | android:focusable="true" |
| 50 | android:gravity="center" | 49 | android:gravity="center" |
| 51 | android:nextFocusLeft="@id/addon_container" | 50 | android:layout_marginEnd="8dp" |
| 52 | app:layout_constraintBottom_toBottomOf="parent" | 51 | app:layout_constraintTop_toTopOf="@+id/text_container" |
| 52 | app:layout_constraintBottom_toBottomOf="@+id/text_container" | ||
| 53 | app:layout_constraintEnd_toStartOf="@+id/button_delete" /> | ||
| 54 | |||
| 55 | <Button | ||
| 56 | android:id="@+id/button_delete" | ||
| 57 | style="@style/Widget.Material3.Button.IconButton" | ||
| 58 | android:layout_width="wrap_content" | ||
| 59 | android:layout_height="wrap_content" | ||
| 60 | android:layout_gravity="center_vertical" | ||
| 61 | android:contentDescription="@string/delete" | ||
| 62 | android:tooltipText="@string/delete" | ||
| 63 | app:icon="@drawable/ic_delete" | ||
| 64 | app:iconTint="?attr/colorControlNormal" | ||
| 53 | app:layout_constraintEnd_toEndOf="parent" | 65 | app:layout_constraintEnd_toEndOf="parent" |
| 54 | app:layout_constraintStart_toEndOf="@id/text_container" | 66 | app:layout_constraintTop_toTopOf="@+id/addon_checkbox" |
| 55 | app:layout_constraintTop_toTopOf="parent" /> | 67 | app:layout_constraintBottom_toBottomOf="@+id/addon_checkbox" /> |
| 56 | 68 | ||
| 57 | </androidx.constraintlayout.widget.ConstraintLayout> | 69 | </androidx.constraintlayout.widget.ConstraintLayout> |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 547752bda..db5b27d38 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -286,6 +286,7 @@ | |||
| 286 | <string name="custom">Custom</string> | 286 | <string name="custom">Custom</string> |
| 287 | <string name="notice">Notice</string> | 287 | <string name="notice">Notice</string> |
| 288 | <string name="import_complete">Import complete</string> | 288 | <string name="import_complete">Import complete</string> |
| 289 | <string name="more_options">More options</string> | ||
| 289 | 290 | ||
| 290 | <!-- GPU driver installation --> | 291 | <!-- GPU driver installation --> |
| 291 | <string name="select_gpu_driver">Select GPU driver</string> | 292 | <string name="select_gpu_driver">Select GPU driver</string> |
| @@ -348,6 +349,8 @@ | |||
| 348 | <string name="verifying_content">Verifying content…</string> | 349 | <string name="verifying_content">Verifying content…</string> |
| 349 | <string name="content_install_notice">Content install notice</string> | 350 | <string name="content_install_notice">Content install notice</string> |
| 350 | <string name="content_install_notice_description">The content that you selected does not match this game.\nInstall anyway?</string> | 351 | <string name="content_install_notice_description">The content that you selected does not match this game.\nInstall anyway?</string> |
| 352 | <string name="confirm_uninstall">Confirm uninstall</string> | ||
| 353 | <string name="confirm_uninstall_description">Are you sure you want to uninstall this addon?</string> | ||
| 351 | 354 | ||
| 352 | <!-- ROM loading errors --> | 355 | <!-- ROM loading errors --> |
| 353 | <string name="loader_error_encrypted">Your ROM is encrypted</string> | 356 | <string name="loader_error_encrypted">Your ROM is encrypted</string> |
diff --git a/src/common/fs/file.h b/src/common/fs/file.h index 167c4d826..2e2396075 100644 --- a/src/common/fs/file.h +++ b/src/common/fs/file.h | |||
| @@ -37,7 +37,7 @@ void OpenFileStream(FileStream& file_stream, const std::filesystem::path& path, | |||
| 37 | template <typename FileStream, typename Path> | 37 | template <typename FileStream, typename Path> |
| 38 | void OpenFileStream(FileStream& file_stream, const Path& path, std::ios_base::openmode open_mode) { | 38 | void OpenFileStream(FileStream& file_stream, const Path& path, std::ios_base::openmode open_mode) { |
| 39 | if constexpr (IsChar<typename Path::value_type>) { | 39 | if constexpr (IsChar<typename Path::value_type>) { |
| 40 | file_stream.open(ToU8String(path), open_mode); | 40 | file_stream.open(std::filesystem::path{ToU8String(path)}, open_mode); |
| 41 | } else { | 41 | } else { |
| 42 | file_stream.open(std::filesystem::path{path}, open_mode); | 42 | file_stream.open(std::filesystem::path{path}, open_mode); |
| 43 | } | 43 | } |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 293d9647b..16ddb5e90 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -712,22 +712,23 @@ add_library(core STATIC | |||
| 712 | hle/service/server_manager.h | 712 | hle/service/server_manager.h |
| 713 | hle/service/service.cpp | 713 | hle/service/service.cpp |
| 714 | hle/service/service.h | 714 | hle/service/service.h |
| 715 | hle/service/set/appln_settings.cpp | 715 | hle/service/set/setting_formats/appln_settings.cpp |
| 716 | hle/service/set/appln_settings.h | 716 | hle/service/set/setting_formats/appln_settings.h |
| 717 | hle/service/set/device_settings.cpp | 717 | hle/service/set/setting_formats/device_settings.cpp |
| 718 | hle/service/set/device_settings.h | 718 | hle/service/set/setting_formats/device_settings.h |
| 719 | hle/service/set/setting_formats/system_settings.cpp | ||
| 720 | hle/service/set/setting_formats/system_settings.h | ||
| 721 | hle/service/set/setting_formats/private_settings.cpp | ||
| 722 | hle/service/set/setting_formats/private_settings.h | ||
| 719 | hle/service/set/factory_settings_server.cpp | 723 | hle/service/set/factory_settings_server.cpp |
| 720 | hle/service/set/factory_settings_server.h | 724 | hle/service/set/factory_settings_server.h |
| 721 | hle/service/set/firmware_debug_settings_server.cpp | 725 | hle/service/set/firmware_debug_settings_server.cpp |
| 722 | hle/service/set/firmware_debug_settings_server.h | 726 | hle/service/set/firmware_debug_settings_server.h |
| 723 | hle/service/set/private_settings.cpp | ||
| 724 | hle/service/set/private_settings.h | ||
| 725 | hle/service/set/settings.cpp | 727 | hle/service/set/settings.cpp |
| 726 | hle/service/set/settings.h | 728 | hle/service/set/settings.h |
| 727 | hle/service/set/settings_server.cpp | 729 | hle/service/set/settings_server.cpp |
| 728 | hle/service/set/settings_server.h | 730 | hle/service/set/settings_server.h |
| 729 | hle/service/set/system_settings.cpp | 731 | hle/service/set/settings_types.h |
| 730 | hle/service/set/system_settings.h | ||
| 731 | hle/service/set/system_settings_server.cpp | 732 | hle/service/set/system_settings_server.cpp |
| 732 | hle/service/set/system_settings_server.h | 733 | hle/service/set/system_settings_server.h |
| 733 | hle/service/sm/sm.cpp | 734 | hle/service/sm/sm.cpp |
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 4a3dbc6a3..612122224 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -466,12 +466,12 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs | |||
| 466 | return romfs; | 466 | return romfs; |
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile update_raw) const { | 469 | std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const { |
| 470 | if (title_id == 0) { | 470 | if (title_id == 0) { |
| 471 | return {}; | 471 | return {}; |
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | std::map<std::string, std::string, std::less<>> out; | 474 | std::vector<Patch> out; |
| 475 | const auto& disabled = Settings::values.disabled_addons[title_id]; | 475 | const auto& disabled = Settings::values.disabled_addons[title_id]; |
| 476 | 476 | ||
| 477 | // Game Updates | 477 | // Game Updates |
| @@ -482,20 +482,28 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 482 | 482 | ||
| 483 | const auto update_disabled = | 483 | const auto update_disabled = |
| 484 | std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); | 484 | std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); |
| 485 | const auto update_label = update_disabled ? "[D] Update" : "Update"; | 485 | Patch update_patch = {.enabled = !update_disabled, |
| 486 | .name = "Update", | ||
| 487 | .version = "", | ||
| 488 | .type = PatchType::Update, | ||
| 489 | .program_id = title_id, | ||
| 490 | .title_id = title_id}; | ||
| 486 | 491 | ||
| 487 | if (nacp != nullptr) { | 492 | if (nacp != nullptr) { |
| 488 | out.insert_or_assign(update_label, nacp->GetVersionString()); | 493 | update_patch.version = nacp->GetVersionString(); |
| 494 | out.push_back(update_patch); | ||
| 489 | } else { | 495 | } else { |
| 490 | if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { | 496 | if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) { |
| 491 | const auto meta_ver = content_provider.GetEntryVersion(update_tid); | 497 | const auto meta_ver = content_provider.GetEntryVersion(update_tid); |
| 492 | if (meta_ver.value_or(0) == 0) { | 498 | if (meta_ver.value_or(0) == 0) { |
| 493 | out.insert_or_assign(update_label, ""); | 499 | out.push_back(update_patch); |
| 494 | } else { | 500 | } else { |
| 495 | out.insert_or_assign(update_label, FormatTitleVersion(*meta_ver)); | 501 | update_patch.version = FormatTitleVersion(*meta_ver); |
| 502 | out.push_back(update_patch); | ||
| 496 | } | 503 | } |
| 497 | } else if (update_raw != nullptr) { | 504 | } else if (update_raw != nullptr) { |
| 498 | out.insert_or_assign(update_label, "PACKED"); | 505 | update_patch.version = "PACKED"; |
| 506 | out.push_back(update_patch); | ||
| 499 | } | 507 | } |
| 500 | } | 508 | } |
| 501 | 509 | ||
| @@ -539,7 +547,12 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 539 | 547 | ||
| 540 | const auto mod_disabled = | 548 | const auto mod_disabled = |
| 541 | std::find(disabled.begin(), disabled.end(), mod->GetName()) != disabled.end(); | 549 | std::find(disabled.begin(), disabled.end(), mod->GetName()) != disabled.end(); |
| 542 | out.insert_or_assign(mod_disabled ? "[D] " + mod->GetName() : mod->GetName(), types); | 550 | out.push_back({.enabled = !mod_disabled, |
| 551 | .name = mod->GetName(), | ||
| 552 | .version = types, | ||
| 553 | .type = PatchType::Mod, | ||
| 554 | .program_id = title_id, | ||
| 555 | .title_id = title_id}); | ||
| 543 | } | 556 | } |
| 544 | } | 557 | } |
| 545 | 558 | ||
| @@ -557,7 +570,12 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 557 | if (!types.empty()) { | 570 | if (!types.empty()) { |
| 558 | const auto mod_disabled = | 571 | const auto mod_disabled = |
| 559 | std::find(disabled.begin(), disabled.end(), "SDMC") != disabled.end(); | 572 | std::find(disabled.begin(), disabled.end(), "SDMC") != disabled.end(); |
| 560 | out.insert_or_assign(mod_disabled ? "[D] SDMC" : "SDMC", types); | 573 | out.push_back({.enabled = !mod_disabled, |
| 574 | .name = "SDMC", | ||
| 575 | .version = types, | ||
| 576 | .type = PatchType::Mod, | ||
| 577 | .program_id = title_id, | ||
| 578 | .title_id = title_id}); | ||
| 561 | } | 579 | } |
| 562 | } | 580 | } |
| 563 | 581 | ||
| @@ -584,7 +602,12 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u | |||
| 584 | 602 | ||
| 585 | const auto dlc_disabled = | 603 | const auto dlc_disabled = |
| 586 | std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end(); | 604 | std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end(); |
| 587 | out.insert_or_assign(dlc_disabled ? "[D] DLC" : "DLC", std::move(list)); | 605 | out.push_back({.enabled = !dlc_disabled, |
| 606 | .name = "DLC", | ||
| 607 | .version = std::move(list), | ||
| 608 | .type = PatchType::DLC, | ||
| 609 | .program_id = title_id, | ||
| 610 | .title_id = dlc_match.back().title_id}); | ||
| 588 | } | 611 | } |
| 589 | 612 | ||
| 590 | return out; | 613 | return out; |
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index 03e9c7301..2601b8217 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h | |||
| @@ -26,12 +26,22 @@ class ContentProvider; | |||
| 26 | class NCA; | 26 | class NCA; |
| 27 | class NACP; | 27 | class NACP; |
| 28 | 28 | ||
| 29 | enum class PatchType { Update, DLC, Mod }; | ||
| 30 | |||
| 31 | struct Patch { | ||
| 32 | bool enabled; | ||
| 33 | std::string name; | ||
| 34 | std::string version; | ||
| 35 | PatchType type; | ||
| 36 | u64 program_id; | ||
| 37 | u64 title_id; | ||
| 38 | }; | ||
| 39 | |||
| 29 | // A centralized class to manage patches to games. | 40 | // A centralized class to manage patches to games. |
| 30 | class PatchManager { | 41 | class PatchManager { |
| 31 | public: | 42 | public: |
| 32 | using BuildID = std::array<u8, 0x20>; | 43 | using BuildID = std::array<u8, 0x20>; |
| 33 | using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>; | 44 | using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>; |
| 34 | using PatchVersionNames = std::map<std::string, std::string, std::less<>>; | ||
| 35 | 45 | ||
| 36 | explicit PatchManager(u64 title_id_, | 46 | explicit PatchManager(u64 title_id_, |
| 37 | const Service::FileSystem::FileSystemController& fs_controller_, | 47 | const Service::FileSystem::FileSystemController& fs_controller_, |
| @@ -66,9 +76,8 @@ public: | |||
| 66 | VirtualFile packed_update_raw = nullptr, | 76 | VirtualFile packed_update_raw = nullptr, |
| 67 | bool apply_layeredfs = true) const; | 77 | bool apply_layeredfs = true) const; |
| 68 | 78 | ||
| 69 | // Returns a vector of pairs between patch names and patch versions. | 79 | // Returns a vector of patches |
| 70 | // i.e. Update 3.2.2 will return {"Update", "3.2.2"} | 80 | [[nodiscard]] std::vector<Patch> GetPatches(VirtualFile update_raw = nullptr) const; |
| 71 | [[nodiscard]] PatchVersionNames GetPatchVersionNames(VirtualFile update_raw = nullptr) const; | ||
| 72 | 81 | ||
| 73 | // If the game update exists, returns the u32 version field in its Meta-type NCA. If that fails, | 82 | // If the game update exists, returns the u32 version field in its Meta-type NCA. If that fails, |
| 74 | // it will fallback to the Meta-type NCA of the base game. If that fails, the result will be | 83 | // it will fallback to the Meta-type NCA of the base game. If that fails, the result will be |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 683f44e27..29a10ad13 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "common/fs/path_util.h" | 11 | #include "common/fs/path_util.h" |
| 12 | #include "common/polyfill_ranges.h" | 12 | #include "common/polyfill_ranges.h" |
| 13 | #include "common/settings.h" | 13 | #include "common/settings.h" |
| 14 | #include "common/string_util.h" | ||
| 14 | #include "core/hle/service/acc/profile_manager.h" | 15 | #include "core/hle/service/acc/profile_manager.h" |
| 15 | 16 | ||
| 16 | namespace Service::Account { | 17 | namespace Service::Account { |
| @@ -164,6 +165,22 @@ std::optional<std::size_t> ProfileManager::GetUserIndex(const ProfileInfo& user) | |||
| 164 | return GetUserIndex(user.user_uuid); | 165 | return GetUserIndex(user.user_uuid); |
| 165 | } | 166 | } |
| 166 | 167 | ||
| 168 | /// Returns the first user profile seen based on username (which does not enforce uniqueness) | ||
| 169 | std::optional<std::size_t> ProfileManager::GetUserIndex(const std::string& username) const { | ||
| 170 | const auto iter = | ||
| 171 | std::find_if(profiles.begin(), profiles.end(), [&username](const ProfileInfo& p) { | ||
| 172 | const std::string profile_username = Common::StringFromFixedZeroTerminatedBuffer( | ||
| 173 | reinterpret_cast<const char*>(p.username.data()), p.username.size()); | ||
| 174 | |||
| 175 | return username.compare(profile_username) == 0; | ||
| 176 | }); | ||
| 177 | if (iter == profiles.end()) { | ||
| 178 | return std::nullopt; | ||
| 179 | } | ||
| 180 | |||
| 181 | return static_cast<std::size_t>(std::distance(profiles.begin(), iter)); | ||
| 182 | } | ||
| 183 | |||
| 167 | /// Returns the data structure used by the switch when GetProfileBase is called on acc:* | 184 | /// Returns the data structure used by the switch when GetProfileBase is called on acc:* |
| 168 | bool ProfileManager::GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const { | 185 | bool ProfileManager::GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const { |
| 169 | if (!index || index >= MAX_USERS) { | 186 | if (!index || index >= MAX_USERS) { |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index e21863e64..f94157300 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -70,6 +70,7 @@ public: | |||
| 70 | std::optional<Common::UUID> GetUser(std::size_t index) const; | 70 | std::optional<Common::UUID> GetUser(std::size_t index) const; |
| 71 | std::optional<std::size_t> GetUserIndex(const Common::UUID& uuid) const; | 71 | std::optional<std::size_t> GetUserIndex(const Common::UUID& uuid) const; |
| 72 | std::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const; | 72 | std::optional<std::size_t> GetUserIndex(const ProfileInfo& user) const; |
| 73 | std::optional<std::size_t> GetUserIndex(const std::string& username) const; | ||
| 73 | bool GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const; | 74 | bool GetProfileBase(std::optional<std::size_t> index, ProfileBase& profile) const; |
| 74 | bool GetProfileBase(Common::UUID uuid, ProfileBase& profile) const; | 75 | bool GetProfileBase(Common::UUID uuid, ProfileBase& profile) const; |
| 75 | bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const; | 76 | bool GetProfileBase(const ProfileInfo& user, ProfileBase& profile) const; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 4ce0a9834..595a3372e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -20,12 +20,13 @@ void LoopProcess(Core::System& system) { | |||
| 20 | auto server_manager = std::make_unique<ServerManager>(system); | 20 | auto server_manager = std::make_unique<ServerManager>(system); |
| 21 | std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system); | 21 | std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system); |
| 22 | std::shared_ptr<HidFirmwareSettings> firmware_settings = | 22 | std::shared_ptr<HidFirmwareSettings> firmware_settings = |
| 23 | std::make_shared<HidFirmwareSettings>(); | 23 | std::make_shared<HidFirmwareSettings>(system); |
| 24 | 24 | ||
| 25 | // TODO: Remove this hack when am is emulated properly. | 25 | // TODO: Remove this hack when am is emulated properly. |
| 26 | resource_manager->Initialize(); | 26 | resource_manager->Initialize(); |
| 27 | resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), | 27 | resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), |
| 28 | true); | 28 | true); |
| 29 | resource_manager->SetAruidValidForVibration(system.ApplicationProcess()->GetProcessId(), true); | ||
| 29 | 30 | ||
| 30 | server_manager->RegisterNamedService( | 31 | server_manager->RegisterNamedService( |
| 31 | "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); | 32 | "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); |
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index 1951da33b..30afed812 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp | |||
| @@ -22,12 +22,16 @@ | |||
| 22 | #include "hid_core/resources/mouse/mouse.h" | 22 | #include "hid_core/resources/mouse/mouse.h" |
| 23 | #include "hid_core/resources/npad/npad.h" | 23 | #include "hid_core/resources/npad/npad.h" |
| 24 | #include "hid_core/resources/npad/npad_types.h" | 24 | #include "hid_core/resources/npad/npad_types.h" |
| 25 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 25 | #include "hid_core/resources/palma/palma.h" | 26 | #include "hid_core/resources/palma/palma.h" |
| 26 | #include "hid_core/resources/six_axis/console_six_axis.h" | 27 | #include "hid_core/resources/six_axis/console_six_axis.h" |
| 27 | #include "hid_core/resources/six_axis/seven_six_axis.h" | 28 | #include "hid_core/resources/six_axis/seven_six_axis.h" |
| 28 | #include "hid_core/resources/six_axis/six_axis.h" | 29 | #include "hid_core/resources/six_axis/six_axis.h" |
| 29 | #include "hid_core/resources/touch_screen/gesture.h" | 30 | #include "hid_core/resources/touch_screen/gesture.h" |
| 30 | #include "hid_core/resources/touch_screen/touch_screen.h" | 31 | #include "hid_core/resources/touch_screen/touch_screen.h" |
| 32 | #include "hid_core/resources/vibration/gc_vibration_device.h" | ||
| 33 | #include "hid_core/resources/vibration/n64_vibration_device.h" | ||
| 34 | #include "hid_core/resources/vibration/vibration_device.h" | ||
| 31 | 35 | ||
| 32 | namespace Service::HID { | 36 | namespace Service::HID { |
| 33 | 37 | ||
| @@ -38,7 +42,7 @@ public: | |||
| 38 | : ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) { | 42 | : ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) { |
| 39 | // clang-format off | 43 | // clang-format off |
| 40 | static const FunctionInfo functions[] = { | 44 | static const FunctionInfo functions[] = { |
| 41 | {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"}, | 45 | {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"}, |
| 42 | }; | 46 | }; |
| 43 | // clang-format on | 47 | // clang-format on |
| 44 | 48 | ||
| @@ -46,22 +50,49 @@ public: | |||
| 46 | } | 50 | } |
| 47 | 51 | ||
| 48 | private: | 52 | private: |
| 49 | void InitializeVibrationDevice(HLERequestContext& ctx) { | 53 | void ActivateVibrationDevice(HLERequestContext& ctx) { |
| 50 | IPC::RequestParser rp{ctx}; | 54 | IPC::RequestParser rp{ctx}; |
| 51 | const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; | 55 | const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; |
| 52 | 56 | ||
| 53 | if (resource_manager != nullptr && resource_manager->GetNpad()) { | ||
| 54 | resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle); | ||
| 55 | } | ||
| 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={}", |
| 58 | vibration_device_handle.npad_type, vibration_device_handle.npad_id, | 58 | vibration_device_handle.npad_type, vibration_device_handle.npad_id, |
| 59 | vibration_device_handle.device_index); | 59 | vibration_device_handle.device_index); |
| 60 | 60 | ||
| 61 | const auto result = ActivateVibrationDeviceImpl(vibration_device_handle); | ||
| 62 | |||
| 61 | IPC::ResponseBuilder rb{ctx, 2}; | 63 | IPC::ResponseBuilder rb{ctx, 2}; |
| 62 | rb.Push(ResultSuccess); | 64 | rb.Push(result); |
| 63 | } | 65 | } |
| 64 | 66 | ||
| 67 | Result ActivateVibrationDeviceImpl(const Core::HID::VibrationDeviceHandle& handle) { | ||
| 68 | std::scoped_lock lock{mutex}; | ||
| 69 | |||
| 70 | const Result is_valid = IsVibrationHandleValid(handle); | ||
| 71 | if (is_valid.IsError()) { | ||
| 72 | return is_valid; | ||
| 73 | } | ||
| 74 | |||
| 75 | for (std::size_t i = 0; i < list_size; i++) { | ||
| 76 | if (handle.device_index == vibration_device_list[i].device_index && | ||
| 77 | handle.npad_id == vibration_device_list[i].npad_id && | ||
| 78 | handle.npad_type == vibration_device_list[i].npad_type) { | ||
| 79 | return ResultSuccess; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | if (list_size == vibration_device_list.size()) { | ||
| 83 | return ResultVibrationDeviceIndexOutOfRange; | ||
| 84 | } | ||
| 85 | const Result result = resource_manager->GetVibrationDevice(handle)->Activate(); | ||
| 86 | if (result.IsError()) { | ||
| 87 | return result; | ||
| 88 | } | ||
| 89 | vibration_device_list[list_size++] = handle; | ||
| 90 | return ResultSuccess; | ||
| 91 | } | ||
| 92 | |||
| 93 | mutable std::mutex mutex; | ||
| 94 | std::size_t list_size{}; | ||
| 95 | std::array<Core::HID::VibrationDeviceHandle, 0x100> vibration_device_list{}; | ||
| 65 | std::shared_ptr<ResourceManager> resource_manager; | 96 | std::shared_ptr<ResourceManager> resource_manager; |
| 66 | }; | 97 | }; |
| 67 | 98 | ||
| @@ -153,7 +184,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r | |||
| 153 | {209, &IHidServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, | 184 | {209, &IHidServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, |
| 154 | {210, &IHidServer::EndPermitVibrationSession, "EndPermitVibrationSession"}, | 185 | {210, &IHidServer::EndPermitVibrationSession, "EndPermitVibrationSession"}, |
| 155 | {211, &IHidServer::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"}, | 186 | {211, &IHidServer::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"}, |
| 156 | {212, nullptr, "SendVibrationValueInBool"}, | 187 | {212, &IHidServer::SendVibrationValueInBool, "SendVibrationValueInBool"}, |
| 157 | {300, &IHidServer::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, | 188 | {300, &IHidServer::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, |
| 158 | {301, &IHidServer::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, | 189 | {301, &IHidServer::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, |
| 159 | {302, &IHidServer::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, | 190 | {302, &IHidServer::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, |
| @@ -1492,59 +1523,13 @@ void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) { | |||
| 1492 | void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { | 1523 | void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { |
| 1493 | IPC::RequestParser rp{ctx}; | 1524 | IPC::RequestParser rp{ctx}; |
| 1494 | const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; | 1525 | const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()}; |
| 1495 | const auto controller = GetResourceManager()->GetNpad(); | ||
| 1496 | |||
| 1497 | Core::HID::VibrationDeviceInfo vibration_device_info; | ||
| 1498 | bool check_device_index = false; | ||
| 1499 | |||
| 1500 | switch (vibration_device_handle.npad_type) { | ||
| 1501 | case Core::HID::NpadStyleIndex::Fullkey: | ||
| 1502 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 1503 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 1504 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 1505 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 1506 | vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; | ||
| 1507 | check_device_index = true; | ||
| 1508 | break; | ||
| 1509 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 1510 | vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; | ||
| 1511 | break; | ||
| 1512 | case Core::HID::NpadStyleIndex::N64: | ||
| 1513 | vibration_device_info.type = Core::HID::VibrationDeviceType::N64; | ||
| 1514 | break; | ||
| 1515 | default: | ||
| 1516 | vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; | ||
| 1517 | break; | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | vibration_device_info.position = Core::HID::VibrationDevicePosition::None; | ||
| 1521 | if (check_device_index) { | ||
| 1522 | switch (vibration_device_handle.device_index) { | ||
| 1523 | case Core::HID::DeviceIndex::Left: | ||
| 1524 | vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; | ||
| 1525 | break; | ||
| 1526 | case Core::HID::DeviceIndex::Right: | ||
| 1527 | vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; | ||
| 1528 | break; | ||
| 1529 | case Core::HID::DeviceIndex::None: | ||
| 1530 | default: | ||
| 1531 | ASSERT_MSG(false, "DeviceIndex should never be None!"); | ||
| 1532 | break; | ||
| 1533 | } | ||
| 1534 | } | ||
| 1535 | 1526 | ||
| 1536 | LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", | 1527 | Core::HID::VibrationDeviceInfo vibration_device_info{}; |
| 1537 | vibration_device_info.type, vibration_device_info.position); | 1528 | const auto result = GetResourceManager()->GetVibrationDeviceInfo(vibration_device_info, |
| 1538 | 1529 | vibration_device_handle); | |
| 1539 | const auto result = IsVibrationHandleValid(vibration_device_handle); | ||
| 1540 | if (result.IsError()) { | ||
| 1541 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1542 | rb.Push(result); | ||
| 1543 | return; | ||
| 1544 | } | ||
| 1545 | 1530 | ||
| 1546 | IPC::ResponseBuilder rb{ctx, 4}; | 1531 | IPC::ResponseBuilder rb{ctx, 4}; |
| 1547 | rb.Push(ResultSuccess); | 1532 | rb.Push(result); |
| 1548 | rb.PushRaw(vibration_device_info); | 1533 | rb.PushRaw(vibration_device_info); |
| 1549 | } | 1534 | } |
| 1550 | 1535 | ||
| @@ -1560,16 +1545,16 @@ void IHidServer::SendVibrationValue(HLERequestContext& ctx) { | |||
| 1560 | 1545 | ||
| 1561 | const auto parameters{rp.PopRaw<Parameters>()}; | 1546 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1562 | 1547 | ||
| 1563 | GetResourceManager()->GetNpad()->VibrateController(parameters.applet_resource_user_id, | ||
| 1564 | parameters.vibration_device_handle, | ||
| 1565 | parameters.vibration_value); | ||
| 1566 | |||
| 1567 | LOG_DEBUG(Service_HID, | 1548 | LOG_DEBUG(Service_HID, |
| 1568 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 1549 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| 1569 | parameters.vibration_device_handle.npad_type, | 1550 | parameters.vibration_device_handle.npad_type, |
| 1570 | parameters.vibration_device_handle.npad_id, | 1551 | parameters.vibration_device_handle.npad_id, |
| 1571 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); | 1552 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); |
| 1572 | 1553 | ||
| 1554 | GetResourceManager()->SendVibrationValue(parameters.applet_resource_user_id, | ||
| 1555 | parameters.vibration_device_handle, | ||
| 1556 | parameters.vibration_value); | ||
| 1557 | |||
| 1573 | IPC::ResponseBuilder rb{ctx, 2}; | 1558 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1574 | rb.Push(ResultSuccess); | 1559 | rb.Push(ResultSuccess); |
| 1575 | } | 1560 | } |
| @@ -1591,10 +1576,28 @@ void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) { | |||
| 1591 | parameters.vibration_device_handle.npad_id, | 1576 | parameters.vibration_device_handle.npad_id, |
| 1592 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); | 1577 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); |
| 1593 | 1578 | ||
| 1579 | bool has_active_aruid{}; | ||
| 1580 | NpadVibrationDevice* device{nullptr}; | ||
| 1581 | Core::HID::VibrationValue vibration_value{}; | ||
| 1582 | Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id, | ||
| 1583 | has_active_aruid); | ||
| 1584 | |||
| 1585 | if (result.IsSuccess() && has_active_aruid) { | ||
| 1586 | result = IsVibrationHandleValid(parameters.vibration_device_handle); | ||
| 1587 | } | ||
| 1588 | if (result.IsSuccess() && has_active_aruid) { | ||
| 1589 | device = GetResourceManager()->GetNSVibrationDevice(parameters.vibration_device_handle); | ||
| 1590 | } | ||
| 1591 | if (device != nullptr) { | ||
| 1592 | result = device->GetActualVibrationValue(vibration_value); | ||
| 1593 | } | ||
| 1594 | if (result.IsError()) { | ||
| 1595 | vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE; | ||
| 1596 | } | ||
| 1597 | |||
| 1594 | IPC::ResponseBuilder rb{ctx, 6}; | 1598 | IPC::ResponseBuilder rb{ctx, 6}; |
| 1595 | rb.Push(ResultSuccess); | 1599 | rb.Push(ResultSuccess); |
| 1596 | rb.PushRaw(GetResourceManager()->GetNpad()->GetLastVibration( | 1600 | rb.PushRaw(vibration_value); |
| 1597 | parameters.applet_resource_user_id, parameters.vibration_device_handle)); | ||
| 1598 | } | 1601 | } |
| 1599 | 1602 | ||
| 1600 | void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) { | 1603 | void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) { |
| @@ -1609,25 +1612,27 @@ void IHidServer::PermitVibration(HLERequestContext& ctx) { | |||
| 1609 | IPC::RequestParser rp{ctx}; | 1612 | IPC::RequestParser rp{ctx}; |
| 1610 | const auto can_vibrate{rp.Pop<bool>()}; | 1613 | const auto can_vibrate{rp.Pop<bool>()}; |
| 1611 | 1614 | ||
| 1612 | // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value | ||
| 1613 | // by converting it to a bool | ||
| 1614 | Settings::values.vibration_enabled.SetValue(can_vibrate); | ||
| 1615 | |||
| 1616 | LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); | 1615 | LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); |
| 1617 | 1616 | ||
| 1617 | const auto result = | ||
| 1618 | GetResourceManager()->GetNpad()->GetVibrationHandler()->SetVibrationMasterVolume( | ||
| 1619 | can_vibrate ? 1.0f : 0.0f); | ||
| 1620 | |||
| 1618 | IPC::ResponseBuilder rb{ctx, 2}; | 1621 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1619 | rb.Push(ResultSuccess); | 1622 | rb.Push(result); |
| 1620 | } | 1623 | } |
| 1621 | 1624 | ||
| 1622 | void IHidServer::IsVibrationPermitted(HLERequestContext& ctx) { | 1625 | void IHidServer::IsVibrationPermitted(HLERequestContext& ctx) { |
| 1623 | LOG_DEBUG(Service_HID, "called"); | 1626 | LOG_DEBUG(Service_HID, "called"); |
| 1624 | 1627 | ||
| 1625 | // nnSDK checks if a float is greater than zero. We return the bool we stored earlier | 1628 | f32 master_volume{}; |
| 1626 | const auto is_enabled = Settings::values.vibration_enabled.GetValue(); | 1629 | const auto result = |
| 1630 | GetResourceManager()->GetNpad()->GetVibrationHandler()->GetVibrationMasterVolume( | ||
| 1631 | master_volume); | ||
| 1627 | 1632 | ||
| 1628 | IPC::ResponseBuilder rb{ctx, 3}; | 1633 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1629 | rb.Push(ResultSuccess); | 1634 | rb.Push(result); |
| 1630 | rb.Push(is_enabled); | 1635 | rb.Push(master_volume > 0.0f); |
| 1631 | } | 1636 | } |
| 1632 | 1637 | ||
| 1633 | void IHidServer::SendVibrationValues(HLERequestContext& ctx) { | 1638 | void IHidServer::SendVibrationValues(HLERequestContext& ctx) { |
| @@ -1645,13 +1650,22 @@ void IHidServer::SendVibrationValues(HLERequestContext& ctx) { | |||
| 1645 | auto vibration_values = std::span( | 1650 | auto vibration_values = std::span( |
| 1646 | reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count); | 1651 | reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count); |
| 1647 | 1652 | ||
| 1648 | GetResourceManager()->GetNpad()->VibrateControllers(applet_resource_user_id, | ||
| 1649 | vibration_device_handles, vibration_values); | ||
| 1650 | |||
| 1651 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1653 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 1652 | 1654 | ||
| 1655 | Result result = ResultSuccess; | ||
| 1656 | if (handle_count != vibration_count) { | ||
| 1657 | result = ResultVibrationArraySizeMismatch; | ||
| 1658 | } | ||
| 1659 | |||
| 1660 | for (std::size_t i = 0; i < handle_count; i++) { | ||
| 1661 | if (result.IsSuccess()) { | ||
| 1662 | result = GetResourceManager()->SendVibrationValue( | ||
| 1663 | applet_resource_user_id, vibration_device_handles[i], vibration_values[i]); | ||
| 1664 | } | ||
| 1665 | } | ||
| 1666 | |||
| 1653 | IPC::ResponseBuilder rb{ctx, 2}; | 1667 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1654 | rb.Push(ResultSuccess); | 1668 | rb.Push(result); |
| 1655 | } | 1669 | } |
| 1656 | 1670 | ||
| 1657 | void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { | 1671 | void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { |
| @@ -1666,43 +1680,6 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { | |||
| 1666 | 1680 | ||
| 1667 | const auto parameters{rp.PopRaw<Parameters>()}; | 1681 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1668 | 1682 | ||
| 1669 | /** | ||
| 1670 | * Note: This uses yuzu-specific behavior such that the StopHard command produces | ||
| 1671 | * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below, | ||
| 1672 | * in order to differentiate between Stop and StopHard commands. | ||
| 1673 | * This is done to reuse the controller vibration functions made for regular controllers. | ||
| 1674 | */ | ||
| 1675 | const auto vibration_value = [parameters] { | ||
| 1676 | switch (parameters.gc_erm_command) { | ||
| 1677 | case Core::HID::VibrationGcErmCommand::Stop: | ||
| 1678 | return Core::HID::VibrationValue{ | ||
| 1679 | .low_amplitude = 0.0f, | ||
| 1680 | .low_frequency = 160.0f, | ||
| 1681 | .high_amplitude = 0.0f, | ||
| 1682 | .high_frequency = 320.0f, | ||
| 1683 | }; | ||
| 1684 | case Core::HID::VibrationGcErmCommand::Start: | ||
| 1685 | return Core::HID::VibrationValue{ | ||
| 1686 | .low_amplitude = 1.0f, | ||
| 1687 | .low_frequency = 160.0f, | ||
| 1688 | .high_amplitude = 1.0f, | ||
| 1689 | .high_frequency = 320.0f, | ||
| 1690 | }; | ||
| 1691 | case Core::HID::VibrationGcErmCommand::StopHard: | ||
| 1692 | return Core::HID::VibrationValue{ | ||
| 1693 | .low_amplitude = 0.0f, | ||
| 1694 | .low_frequency = 0.0f, | ||
| 1695 | .high_amplitude = 0.0f, | ||
| 1696 | .high_frequency = 0.0f, | ||
| 1697 | }; | ||
| 1698 | default: | ||
| 1699 | return Core::HID::DEFAULT_VIBRATION_VALUE; | ||
| 1700 | } | ||
| 1701 | }(); | ||
| 1702 | |||
| 1703 | GetResourceManager()->GetNpad()->VibrateController( | ||
| 1704 | parameters.applet_resource_user_id, parameters.vibration_device_handle, vibration_value); | ||
| 1705 | |||
| 1706 | LOG_DEBUG(Service_HID, | 1683 | LOG_DEBUG(Service_HID, |
| 1707 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " | 1684 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " |
| 1708 | "gc_erm_command={}", | 1685 | "gc_erm_command={}", |
| @@ -1711,8 +1688,23 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) { | |||
| 1711 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id, | 1688 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id, |
| 1712 | parameters.gc_erm_command); | 1689 | parameters.gc_erm_command); |
| 1713 | 1690 | ||
| 1691 | bool has_active_aruid{}; | ||
| 1692 | NpadGcVibrationDevice* gc_device{nullptr}; | ||
| 1693 | Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id, | ||
| 1694 | has_active_aruid); | ||
| 1695 | |||
| 1696 | if (result.IsSuccess() && has_active_aruid) { | ||
| 1697 | result = IsVibrationHandleValid(parameters.vibration_device_handle); | ||
| 1698 | } | ||
| 1699 | if (result.IsSuccess() && has_active_aruid) { | ||
| 1700 | gc_device = GetResourceManager()->GetGcVibrationDevice(parameters.vibration_device_handle); | ||
| 1701 | } | ||
| 1702 | if (gc_device != nullptr) { | ||
| 1703 | result = gc_device->SendVibrationGcErmCommand(parameters.gc_erm_command); | ||
| 1704 | } | ||
| 1705 | |||
| 1714 | IPC::ResponseBuilder rb{ctx, 2}; | 1706 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1715 | rb.Push(ResultSuccess); | 1707 | rb.Push(result); |
| 1716 | } | 1708 | } |
| 1717 | 1709 | ||
| 1718 | void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) { | 1710 | void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) { |
| @@ -1725,33 +1717,31 @@ void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) { | |||
| 1725 | 1717 | ||
| 1726 | const auto parameters{rp.PopRaw<Parameters>()}; | 1718 | const auto parameters{rp.PopRaw<Parameters>()}; |
| 1727 | 1719 | ||
| 1728 | const auto last_vibration = GetResourceManager()->GetNpad()->GetLastVibration( | ||
| 1729 | parameters.applet_resource_user_id, parameters.vibration_device_handle); | ||
| 1730 | |||
| 1731 | const auto gc_erm_command = [last_vibration] { | ||
| 1732 | if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { | ||
| 1733 | return Core::HID::VibrationGcErmCommand::Start; | ||
| 1734 | } | ||
| 1735 | |||
| 1736 | /** | ||
| 1737 | * Note: This uses yuzu-specific behavior such that the StopHard command produces | ||
| 1738 | * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function | ||
| 1739 | * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands. | ||
| 1740 | * This is done to reuse the controller vibration functions made for regular controllers. | ||
| 1741 | */ | ||
| 1742 | if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) { | ||
| 1743 | return Core::HID::VibrationGcErmCommand::StopHard; | ||
| 1744 | } | ||
| 1745 | |||
| 1746 | return Core::HID::VibrationGcErmCommand::Stop; | ||
| 1747 | }(); | ||
| 1748 | |||
| 1749 | LOG_DEBUG(Service_HID, | 1720 | LOG_DEBUG(Service_HID, |
| 1750 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", | 1721 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", |
| 1751 | parameters.vibration_device_handle.npad_type, | 1722 | parameters.vibration_device_handle.npad_type, |
| 1752 | parameters.vibration_device_handle.npad_id, | 1723 | parameters.vibration_device_handle.npad_id, |
| 1753 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); | 1724 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); |
| 1754 | 1725 | ||
| 1726 | bool has_active_aruid{}; | ||
| 1727 | NpadGcVibrationDevice* gc_device{nullptr}; | ||
| 1728 | Core::HID::VibrationGcErmCommand gc_erm_command{}; | ||
| 1729 | Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id, | ||
| 1730 | has_active_aruid); | ||
| 1731 | |||
| 1732 | if (result.IsSuccess() && has_active_aruid) { | ||
| 1733 | result = IsVibrationHandleValid(parameters.vibration_device_handle); | ||
| 1734 | } | ||
| 1735 | if (result.IsSuccess() && has_active_aruid) { | ||
| 1736 | gc_device = GetResourceManager()->GetGcVibrationDevice(parameters.vibration_device_handle); | ||
| 1737 | } | ||
| 1738 | if (gc_device != nullptr) { | ||
| 1739 | result = gc_device->GetActualVibrationGcErmCommand(gc_erm_command); | ||
| 1740 | } | ||
| 1741 | if (result.IsError()) { | ||
| 1742 | gc_erm_command = Core::HID::VibrationGcErmCommand::Stop; | ||
| 1743 | } | ||
| 1744 | |||
| 1755 | IPC::ResponseBuilder rb{ctx, 4}; | 1745 | IPC::ResponseBuilder rb{ctx, 4}; |
| 1756 | rb.Push(ResultSuccess); | 1746 | rb.Push(ResultSuccess); |
| 1757 | rb.PushEnum(gc_erm_command); | 1747 | rb.PushEnum(gc_erm_command); |
| @@ -1761,21 +1751,24 @@ void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) { | |||
| 1761 | IPC::RequestParser rp{ctx}; | 1751 | IPC::RequestParser rp{ctx}; |
| 1762 | const auto applet_resource_user_id{rp.Pop<u64>()}; | 1752 | const auto applet_resource_user_id{rp.Pop<u64>()}; |
| 1763 | 1753 | ||
| 1764 | GetResourceManager()->GetNpad()->SetPermitVibrationSession(true); | ||
| 1765 | |||
| 1766 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | 1754 | LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); |
| 1767 | 1755 | ||
| 1756 | const auto result = | ||
| 1757 | GetResourceManager()->GetNpad()->GetVibrationHandler()->BeginPermitVibrationSession( | ||
| 1758 | applet_resource_user_id); | ||
| 1759 | |||
| 1768 | IPC::ResponseBuilder rb{ctx, 2}; | 1760 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1769 | rb.Push(ResultSuccess); | 1761 | rb.Push(result); |
| 1770 | } | 1762 | } |
| 1771 | 1763 | ||
| 1772 | void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) { | 1764 | void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) { |
| 1773 | GetResourceManager()->GetNpad()->SetPermitVibrationSession(false); | ||
| 1774 | |||
| 1775 | LOG_DEBUG(Service_HID, "called"); | 1765 | LOG_DEBUG(Service_HID, "called"); |
| 1776 | 1766 | ||
| 1767 | const auto result = | ||
| 1768 | GetResourceManager()->GetNpad()->GetVibrationHandler()->EndPermitVibrationSession(); | ||
| 1769 | |||
| 1777 | IPC::ResponseBuilder rb{ctx, 2}; | 1770 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1778 | rb.Push(ResultSuccess); | 1771 | rb.Push(result); |
| 1779 | } | 1772 | } |
| 1780 | 1773 | ||
| 1781 | void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) { | 1774 | void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) { |
| @@ -1795,10 +1788,61 @@ void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) { | |||
| 1795 | parameters.vibration_device_handle.npad_id, | 1788 | parameters.vibration_device_handle.npad_id, |
| 1796 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); | 1789 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id); |
| 1797 | 1790 | ||
| 1791 | bool is_mounted{}; | ||
| 1792 | NpadVibrationBase* device{nullptr}; | ||
| 1793 | Result result = IsVibrationHandleValid(parameters.vibration_device_handle); | ||
| 1794 | |||
| 1795 | if (result.IsSuccess()) { | ||
| 1796 | device = GetResourceManager()->GetVibrationDevice(parameters.vibration_device_handle); | ||
| 1797 | } | ||
| 1798 | |||
| 1799 | if (device != nullptr) { | ||
| 1800 | is_mounted = device->IsVibrationMounted(); | ||
| 1801 | } | ||
| 1802 | |||
| 1798 | IPC::ResponseBuilder rb{ctx, 3}; | 1803 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1799 | rb.Push(ResultSuccess); | 1804 | rb.Push(result); |
| 1800 | rb.Push(GetResourceManager()->GetNpad()->IsVibrationDeviceMounted( | 1805 | rb.Push(is_mounted); |
| 1801 | parameters.applet_resource_user_id, parameters.vibration_device_handle)); | 1806 | } |
| 1807 | |||
| 1808 | void IHidServer::SendVibrationValueInBool(HLERequestContext& ctx) { | ||
| 1809 | IPC::RequestParser rp{ctx}; | ||
| 1810 | struct Parameters { | ||
| 1811 | Core::HID::VibrationDeviceHandle vibration_device_handle; | ||
| 1812 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 1813 | u64 applet_resource_user_id; | ||
| 1814 | bool is_vibrating; | ||
| 1815 | }; | ||
| 1816 | static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); | ||
| 1817 | |||
| 1818 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 1819 | |||
| 1820 | LOG_DEBUG(Service_HID, | ||
| 1821 | "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, " | ||
| 1822 | "is_vibrating={}", | ||
| 1823 | parameters.vibration_device_handle.npad_type, | ||
| 1824 | parameters.vibration_device_handle.npad_id, | ||
| 1825 | parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id, | ||
| 1826 | parameters.is_vibrating); | ||
| 1827 | |||
| 1828 | bool has_active_aruid{}; | ||
| 1829 | NpadN64VibrationDevice* n64_device{nullptr}; | ||
| 1830 | Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id, | ||
| 1831 | has_active_aruid); | ||
| 1832 | |||
| 1833 | if (result.IsSuccess() && has_active_aruid) { | ||
| 1834 | result = IsVibrationHandleValid(parameters.vibration_device_handle); | ||
| 1835 | } | ||
| 1836 | if (result.IsSuccess() && has_active_aruid) { | ||
| 1837 | n64_device = | ||
| 1838 | GetResourceManager()->GetN64VibrationDevice(parameters.vibration_device_handle); | ||
| 1839 | } | ||
| 1840 | if (n64_device != nullptr) { | ||
| 1841 | result = n64_device->SendValueInBool(parameters.is_vibrating); | ||
| 1842 | } | ||
| 1843 | |||
| 1844 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1845 | rb.Push(result); | ||
| 1802 | } | 1846 | } |
| 1803 | 1847 | ||
| 1804 | void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { | 1848 | void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h index cc7c4ebdd..3a2e0a230 100644 --- a/src/core/hle/service/hid/hid_server.h +++ b/src/core/hle/service/hid/hid_server.h | |||
| @@ -97,6 +97,7 @@ private: | |||
| 97 | void BeginPermitVibrationSession(HLERequestContext& ctx); | 97 | void BeginPermitVibrationSession(HLERequestContext& ctx); |
| 98 | void EndPermitVibrationSession(HLERequestContext& ctx); | 98 | void EndPermitVibrationSession(HLERequestContext& ctx); |
| 99 | void IsVibrationDeviceMounted(HLERequestContext& ctx); | 99 | void IsVibrationDeviceMounted(HLERequestContext& ctx); |
| 100 | void SendVibrationValueInBool(HLERequestContext& ctx); | ||
| 100 | void ActivateConsoleSixAxisSensor(HLERequestContext& ctx); | 101 | void ActivateConsoleSixAxisSensor(HLERequestContext& ctx); |
| 101 | void StartConsoleSixAxisSensor(HLERequestContext& ctx); | 102 | void StartConsoleSixAxisSensor(HLERequestContext& ctx); |
| 102 | void StopConsoleSixAxisSensor(HLERequestContext& ctx); | 103 | void StopConsoleSixAxisSensor(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 3a0cb3cb1..4466a189b 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "hid_core/resource_manager.h" | 7 | #include "hid_core/resource_manager.h" |
| 8 | #include "hid_core/resources/npad/npad.h" | 8 | #include "hid_core/resources/npad/npad.h" |
| 9 | #include "hid_core/resources/npad/npad_types.h" | 9 | #include "hid_core/resources/npad/npad_types.h" |
| 10 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 10 | #include "hid_core/resources/palma/palma.h" | 11 | #include "hid_core/resources/palma/palma.h" |
| 11 | #include "hid_core/resources/touch_screen/touch_screen.h" | 12 | #include "hid_core/resources/touch_screen/touch_screen.h" |
| 12 | 13 | ||
| @@ -67,14 +68,14 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour | |||
| 67 | {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"}, | 68 | {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"}, |
| 68 | {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"}, | 69 | {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"}, |
| 69 | {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"}, | 70 | {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"}, |
| 70 | {504, nullptr, "SetAruidValidForVibration"}, | 71 | {504, &IHidSystemServer::SetAruidValidForVibration, "SetAruidValidForVibration"}, |
| 71 | {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"}, | 72 | {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"}, |
| 72 | {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"}, | 73 | {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"}, |
| 73 | {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"}, | 74 | {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"}, |
| 74 | {510, nullptr, "SetVibrationMasterVolume"}, | 75 | {510, &IHidSystemServer::SetVibrationMasterVolume, "SetVibrationMasterVolume"}, |
| 75 | {511, nullptr, "GetVibrationMasterVolume"}, | 76 | {511, &IHidSystemServer::GetVibrationMasterVolume, "GetVibrationMasterVolume"}, |
| 76 | {512, nullptr, "BeginPermitVibrationSession"}, | 77 | {512, &IHidSystemServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, |
| 77 | {513, nullptr, "EndPermitVibrationSession"}, | 78 | {513, &IHidSystemServer::EndPermitVibrationSession, "EndPermitVibrationSession"}, |
| 78 | {514, nullptr, "Unknown514"}, | 79 | {514, nullptr, "Unknown514"}, |
| 79 | {520, nullptr, "EnableHandheldHids"}, | 80 | {520, nullptr, "EnableHandheldHids"}, |
| 80 | {521, nullptr, "DisableHandheldHids"}, | 81 | {521, nullptr, "DisableHandheldHids"}, |
| @@ -156,7 +157,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour | |||
| 156 | {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, | 157 | {1152, nullptr, "SetTouchScreenDefaultConfiguration"}, |
| 157 | {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, | 158 | {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"}, |
| 158 | {1154, nullptr, "IsFirmwareAvailableForNotification"}, | 159 | {1154, nullptr, "IsFirmwareAvailableForNotification"}, |
| 159 | {1155, nullptr, "SetForceHandheldStyleVibration"}, | 160 | {1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"}, |
| 160 | {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, | 161 | {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"}, |
| 161 | {1157, nullptr, "CancelConnectionTrigger"}, | 162 | {1157, nullptr, "CancelConnectionTrigger"}, |
| 162 | {1200, nullptr, "IsButtonConfigSupported"}, | 163 | {1200, nullptr, "IsButtonConfigSupported"}, |
| @@ -538,6 +539,27 @@ void IHidSystemServer::EnableAppletToGetInput(HLERequestContext& ctx) { | |||
| 538 | rb.Push(ResultSuccess); | 539 | rb.Push(ResultSuccess); |
| 539 | } | 540 | } |
| 540 | 541 | ||
| 542 | void IHidSystemServer::SetAruidValidForVibration(HLERequestContext& ctx) { | ||
| 543 | IPC::RequestParser rp{ctx}; | ||
| 544 | struct Parameters { | ||
| 545 | bool is_enabled; | ||
| 546 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 547 | u64 applet_resource_user_id; | ||
| 548 | }; | ||
| 549 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 550 | |||
| 551 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 552 | |||
| 553 | LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", | ||
| 554 | parameters.is_enabled, parameters.applet_resource_user_id); | ||
| 555 | |||
| 556 | GetResourceManager()->SetAruidValidForVibration(parameters.applet_resource_user_id, | ||
| 557 | parameters.is_enabled); | ||
| 558 | |||
| 559 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 560 | rb.Push(ResultSuccess); | ||
| 561 | } | ||
| 562 | |||
| 541 | void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) { | 563 | void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) { |
| 542 | IPC::RequestParser rp{ctx}; | 564 | IPC::RequestParser rp{ctx}; |
| 543 | struct Parameters { | 565 | struct Parameters { |
| @@ -601,6 +623,57 @@ void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) { | |||
| 601 | rb.Push(ResultSuccess); | 623 | rb.Push(ResultSuccess); |
| 602 | } | 624 | } |
| 603 | 625 | ||
| 626 | void IHidSystemServer::SetVibrationMasterVolume(HLERequestContext& ctx) { | ||
| 627 | IPC::RequestParser rp{ctx}; | ||
| 628 | const auto master_volume{rp.Pop<f32>()}; | ||
| 629 | |||
| 630 | LOG_INFO(Service_HID, "called, volume={}", master_volume); | ||
| 631 | |||
| 632 | const auto result = | ||
| 633 | GetResourceManager()->GetNpad()->GetVibrationHandler()->SetVibrationMasterVolume( | ||
| 634 | master_volume); | ||
| 635 | |||
| 636 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 637 | rb.Push(result); | ||
| 638 | } | ||
| 639 | |||
| 640 | void IHidSystemServer::GetVibrationMasterVolume(HLERequestContext& ctx) { | ||
| 641 | f32 master_volume{}; | ||
| 642 | const auto result = | ||
| 643 | GetResourceManager()->GetNpad()->GetVibrationHandler()->GetVibrationMasterVolume( | ||
| 644 | master_volume); | ||
| 645 | |||
| 646 | LOG_INFO(Service_HID, "called, volume={}", master_volume); | ||
| 647 | |||
| 648 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 649 | rb.Push(result); | ||
| 650 | rb.Push(master_volume); | ||
| 651 | } | ||
| 652 | |||
| 653 | void IHidSystemServer::BeginPermitVibrationSession(HLERequestContext& ctx) { | ||
| 654 | IPC::RequestParser rp{ctx}; | ||
| 655 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 656 | |||
| 657 | LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 658 | |||
| 659 | const auto result = | ||
| 660 | GetResourceManager()->GetNpad()->GetVibrationHandler()->BeginPermitVibrationSession( | ||
| 661 | applet_resource_user_id); | ||
| 662 | |||
| 663 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 664 | rb.Push(result); | ||
| 665 | } | ||
| 666 | |||
| 667 | void IHidSystemServer::EndPermitVibrationSession(HLERequestContext& ctx) { | ||
| 668 | LOG_INFO(Service_HID, "called"); | ||
| 669 | |||
| 670 | const auto result = | ||
| 671 | GetResourceManager()->GetNpad()->GetVibrationHandler()->EndPermitVibrationSession(); | ||
| 672 | |||
| 673 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 674 | rb.Push(result); | ||
| 675 | } | ||
| 676 | |||
| 604 | void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) { | 677 | void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) { |
| 605 | const bool is_attached = true; | 678 | const bool is_attached = true; |
| 606 | 679 | ||
| @@ -749,6 +822,19 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx | |||
| 749 | rb.PushRaw(touchscreen_config); | 822 | rb.PushRaw(touchscreen_config); |
| 750 | } | 823 | } |
| 751 | 824 | ||
| 825 | void IHidSystemServer::SetForceHandheldStyleVibration(HLERequestContext& ctx) { | ||
| 826 | IPC::RequestParser rp{ctx}; | ||
| 827 | const auto is_forced{rp.Pop<bool>()}; | ||
| 828 | |||
| 829 | LOG_INFO(Service_HID, "called, is_forced={}", is_forced); | ||
| 830 | |||
| 831 | GetResourceManager()->SetForceHandheldStyleVibration(is_forced); | ||
| 832 | GetResourceManager()->GetNpad()->UpdateHandheldAbstractState(); | ||
| 833 | |||
| 834 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 835 | rb.Push(ResultSuccess); | ||
| 836 | } | ||
| 837 | |||
| 752 | void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) { | 838 | void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) { |
| 753 | const bool is_enabled = false; | 839 | const bool is_enabled = false; |
| 754 | 840 | ||
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h index 0c2634e3f..90a719f02 100644 --- a/src/core/hle/service/hid/hid_system_server.h +++ b/src/core/hle/service/hid/hid_system_server.h | |||
| @@ -42,9 +42,14 @@ private: | |||
| 42 | void RegisterAppletResourceUserId(HLERequestContext& ctx); | 42 | void RegisterAppletResourceUserId(HLERequestContext& ctx); |
| 43 | void UnregisterAppletResourceUserId(HLERequestContext& ctx); | 43 | void UnregisterAppletResourceUserId(HLERequestContext& ctx); |
| 44 | void EnableAppletToGetInput(HLERequestContext& ctx); | 44 | void EnableAppletToGetInput(HLERequestContext& ctx); |
| 45 | void SetAruidValidForVibration(HLERequestContext& ctx); | ||
| 45 | void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); | 46 | void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); |
| 46 | void EnableAppletToGetPadInput(HLERequestContext& ctx); | 47 | void EnableAppletToGetPadInput(HLERequestContext& ctx); |
| 47 | void EnableAppletToGetTouchScreen(HLERequestContext& ctx); | 48 | void EnableAppletToGetTouchScreen(HLERequestContext& ctx); |
| 49 | void SetVibrationMasterVolume(HLERequestContext& ctx); | ||
| 50 | void GetVibrationMasterVolume(HLERequestContext& ctx); | ||
| 51 | void BeginPermitVibrationSession(HLERequestContext& ctx); | ||
| 52 | void EndPermitVibrationSession(HLERequestContext& ctx); | ||
| 48 | void IsJoyConAttachedOnAllRail(HLERequestContext& ctx); | 53 | void IsJoyConAttachedOnAllRail(HLERequestContext& ctx); |
| 49 | void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); | 54 | void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); |
| 50 | void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); | 55 | void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); |
| @@ -61,6 +66,7 @@ private: | |||
| 61 | void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx); | 66 | void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx); |
| 62 | void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); | 67 | void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); |
| 63 | void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); | 68 | void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); |
| 69 | void SetForceHandheldStyleVibration(HLERequestContext& ctx); | ||
| 64 | void IsUsingCustomButtonConfig(HLERequestContext& ctx); | 70 | void IsUsingCustomButtonConfig(HLERequestContext& ctx); |
| 65 | 71 | ||
| 66 | std::shared_ptr<ResourceManager> GetResourceManager(); | 72 | std::shared_ptr<ResourceManager> GetResourceManager(); |
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index 31cc87acc..cc7776efc 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp | |||
| @@ -441,7 +441,10 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target | |||
| 441 | device_state = DeviceState::TagMounted; | 441 | device_state = DeviceState::TagMounted; |
| 442 | mount_target = mount_target_; | 442 | mount_target = mount_target_; |
| 443 | 443 | ||
| 444 | if (!is_corrupted && mount_target != NFP::MountTarget::Rom) { | 444 | const bool create_backup = |
| 445 | mount_target == NFP::MountTarget::All || mount_target == NFP::MountTarget::Ram || | ||
| 446 | (mount_target == NFP::MountTarget::Rom && HasBackup(encrypted_tag_data.uuid).IsError()); | ||
| 447 | if (!is_corrupted && create_backup) { | ||
| 445 | std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File)); | 448 | std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File)); |
| 446 | memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); | 449 | memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data)); |
| 447 | WriteBackupData(encrypted_tag_data.uuid, data); | 450 | WriteBackupData(encrypted_tag_data.uuid, data); |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 0469110e8..af6591370 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp | |||
| @@ -112,9 +112,7 @@ void Nvnflinger::ShutdownLayers() { | |||
| 112 | { | 112 | { |
| 113 | const auto lock_guard = Lock(); | 113 | const auto lock_guard = Lock(); |
| 114 | for (auto& display : displays) { | 114 | for (auto& display : displays) { |
| 115 | for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { | 115 | display.Abandon(); |
| 116 | display.GetLayer(layer).GetConsumer().Abandon(); | ||
| 117 | } | ||
| 118 | } | 116 | } |
| 119 | 117 | ||
| 120 | is_abandoned = true; | 118 | is_abandoned = true; |
| @@ -176,24 +174,28 @@ void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { | |||
| 176 | display.CreateLayer(layer_id, buffer_id, nvdrv->container); | 174 | display.CreateLayer(layer_id, buffer_id, nvdrv->container); |
| 177 | } | 175 | } |
| 178 | 176 | ||
| 179 | void Nvnflinger::OpenLayer(u64 layer_id) { | 177 | bool Nvnflinger::OpenLayer(u64 layer_id) { |
| 180 | const auto lock_guard = Lock(); | 178 | const auto lock_guard = Lock(); |
| 181 | 179 | ||
| 182 | for (auto& display : displays) { | 180 | for (auto& display : displays) { |
| 183 | if (auto* layer = display.FindLayer(layer_id); layer) { | 181 | if (auto* layer = display.FindLayer(layer_id); layer) { |
| 184 | layer->Open(); | 182 | return layer->Open(); |
| 185 | } | 183 | } |
| 186 | } | 184 | } |
| 185 | |||
| 186 | return false; | ||
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | void Nvnflinger::CloseLayer(u64 layer_id) { | 189 | bool Nvnflinger::CloseLayer(u64 layer_id) { |
| 190 | const auto lock_guard = Lock(); | 190 | const auto lock_guard = Lock(); |
| 191 | 191 | ||
| 192 | for (auto& display : displays) { | 192 | for (auto& display : displays) { |
| 193 | if (auto* layer = display.FindLayer(layer_id); layer) { | 193 | if (auto* layer = display.FindLayer(layer_id); layer) { |
| 194 | layer->Close(); | 194 | return layer->Close(); |
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | |||
| 198 | return false; | ||
| 197 | } | 199 | } |
| 198 | 200 | ||
| 199 | void Nvnflinger::DestroyLayer(u64 layer_id) { | 201 | void Nvnflinger::DestroyLayer(u64 layer_id) { |
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 871285764..a60e0ae6b 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h | |||
| @@ -74,10 +74,10 @@ public: | |||
| 74 | [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id); | 74 | [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id); |
| 75 | 75 | ||
| 76 | /// Opens a layer on all displays for the given layer ID. | 76 | /// Opens a layer on all displays for the given layer ID. |
| 77 | void OpenLayer(u64 layer_id); | 77 | bool OpenLayer(u64 layer_id); |
| 78 | 78 | ||
| 79 | /// Closes a layer on all displays for the given layer ID. | 79 | /// Closes a layer on all displays for the given layer ID. |
| 80 | void CloseLayer(u64 layer_id); | 80 | bool CloseLayer(u64 layer_id); |
| 81 | 81 | ||
| 82 | /// Destroys the given layer ID. | 82 | /// Destroys the given layer ID. |
| 83 | void DestroyLayer(u64 layer_id); | 83 | void DestroyLayer(u64 layer_id); |
diff --git a/src/core/hle/service/set/private_settings.h b/src/core/hle/service/set/private_settings.h deleted file mode 100644 index b63eaf45c..000000000 --- a/src/core/hle/service/set/private_settings.h +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "common/bit_field.h" | ||
| 9 | #include "common/common_funcs.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/uuid.h" | ||
| 12 | #include "core/hle/service/time/clock_types.h" | ||
| 13 | |||
| 14 | namespace Service::Set { | ||
| 15 | |||
| 16 | /// This is nn::settings::system::InitialLaunchFlag | ||
| 17 | struct InitialLaunchFlag { | ||
| 18 | union { | ||
| 19 | u32 raw{}; | ||
| 20 | |||
| 21 | BitField<0, 1, u32> InitialLaunchCompletionFlag; | ||
| 22 | BitField<8, 1, u32> InitialLaunchUserAdditionFlag; | ||
| 23 | BitField<16, 1, u32> InitialLaunchTimestampFlag; | ||
| 24 | }; | ||
| 25 | }; | ||
| 26 | static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size"); | ||
| 27 | |||
| 28 | /// This is nn::settings::system::InitialLaunchSettings | ||
| 29 | struct InitialLaunchSettings { | ||
| 30 | InitialLaunchFlag flags; | ||
| 31 | INSERT_PADDING_BYTES(0x4); | ||
| 32 | Service::Time::Clock::SteadyClockTimePoint timestamp; | ||
| 33 | }; | ||
| 34 | static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); | ||
| 35 | |||
| 36 | #pragma pack(push, 4) | ||
| 37 | struct InitialLaunchSettingsPacked { | ||
| 38 | InitialLaunchFlag flags; | ||
| 39 | Service::Time::Clock::SteadyClockTimePoint timestamp; | ||
| 40 | }; | ||
| 41 | #pragma pack(pop) | ||
| 42 | static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, | ||
| 43 | "InitialLaunchSettingsPacked is incorrect size"); | ||
| 44 | |||
| 45 | struct PrivateSettings { | ||
| 46 | std::array<u8, 0x10> reserved_00; | ||
| 47 | |||
| 48 | // nn::settings::system::InitialLaunchSettings | ||
| 49 | InitialLaunchSettings initial_launch_settings; | ||
| 50 | |||
| 51 | std::array<u8, 0x20> reserved_30; | ||
| 52 | |||
| 53 | Common::UUID external_clock_source_id; | ||
| 54 | s64 shutdown_rtc_value; | ||
| 55 | s64 external_steady_clock_internal_offset; | ||
| 56 | |||
| 57 | std::array<u8, 0x60> reserved_70; | ||
| 58 | |||
| 59 | // nn::settings::system::PlatformRegion | ||
| 60 | std::array<u8, 0x4> platform_region; | ||
| 61 | |||
| 62 | std::array<u8, 0x4> reserved_D4; | ||
| 63 | }; | ||
| 64 | static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10); | ||
| 65 | static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50); | ||
| 66 | static_assert(offsetof(PrivateSettings, reserved_70) == 0x70); | ||
| 67 | static_assert(offsetof(PrivateSettings, platform_region) == 0xD0); | ||
| 68 | static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!"); | ||
| 69 | |||
| 70 | PrivateSettings DefaultPrivateSettings(); | ||
| 71 | |||
| 72 | } // namespace Service::Set | ||
diff --git a/src/core/hle/service/set/appln_settings.cpp b/src/core/hle/service/set/setting_formats/appln_settings.cpp index a5d802757..f7c7d5b91 100644 --- a/src/core/hle/service/set/appln_settings.cpp +++ b/src/core/hle/service/set/setting_formats/appln_settings.cpp | |||
| @@ -1,12 +1,16 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 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 "core/hle/service/set/appln_settings.h" | 4 | #include "core/hle/service/set/setting_formats/appln_settings.h" |
| 5 | 5 | ||
| 6 | namespace Service::Set { | 6 | namespace Service::Set { |
| 7 | 7 | ||
| 8 | ApplnSettings DefaultApplnSettings() { | 8 | ApplnSettings DefaultApplnSettings() { |
| 9 | return {}; | 9 | ApplnSettings settings{}; |
| 10 | |||
| 11 | settings.mii_author_id = Common::UUID::MakeDefault(); | ||
| 12 | |||
| 13 | return settings; | ||
| 10 | } | 14 | } |
| 11 | 15 | ||
| 12 | } // namespace Service::Set | 16 | } // namespace Service::Set |
diff --git a/src/core/hle/service/set/appln_settings.h b/src/core/hle/service/set/setting_formats/appln_settings.h index 126375860..ba9af998a 100644 --- a/src/core/hle/service/set/appln_settings.h +++ b/src/core/hle/service/set/setting_formats/appln_settings.h | |||
| @@ -7,24 +7,23 @@ | |||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/uuid.h" | ||
| 11 | #include "core/hle/service/set/settings_types.h" | ||
| 10 | 12 | ||
| 11 | namespace Service::Set { | 13 | namespace Service::Set { |
| 12 | struct ApplnSettings { | 14 | struct ApplnSettings { |
| 13 | std::array<u8, 0x10> reserved_000; | 15 | INSERT_PADDING_BYTES(0x10); // Reserved |
| 14 | 16 | ||
| 15 | // nn::util::Uuid MiiAuthorId, copied from system settings 0x94B0 | 17 | // nn::util::Uuid MiiAuthorId, copied from system settings 0x94B0 |
| 16 | std::array<u8, 0x10> mii_author_id; | 18 | Common::UUID mii_author_id; |
| 17 | 19 | INSERT_PADDING_BYTES(0x30); // Reserved | |
| 18 | std::array<u8, 0x30> reserved_020; | ||
| 19 | 20 | ||
| 20 | // nn::settings::system::ServiceDiscoveryControlSettings | 21 | // nn::settings::system::ServiceDiscoveryControlSettings |
| 21 | std::array<u8, 0x4> service_discovery_control_settings; | 22 | u32 service_discovery_control_settings; |
| 22 | 23 | INSERT_PADDING_BYTES(0x20); // Reserved | |
| 23 | std::array<u8, 0x20> reserved_054; | ||
| 24 | 24 | ||
| 25 | bool in_repair_process_enable_flag; | 25 | bool in_repair_process_enable_flag; |
| 26 | 26 | INSERT_PADDING_BYTES(0x3); | |
| 27 | std::array<u8, 0x3> pad_075; | ||
| 28 | }; | 27 | }; |
| 29 | static_assert(offsetof(ApplnSettings, mii_author_id) == 0x10); | 28 | static_assert(offsetof(ApplnSettings, mii_author_id) == 0x10); |
| 30 | static_assert(offsetof(ApplnSettings, service_discovery_control_settings) == 0x50); | 29 | static_assert(offsetof(ApplnSettings, service_discovery_control_settings) == 0x50); |
diff --git a/src/core/hle/service/set/device_settings.cpp b/src/core/hle/service/set/setting_formats/device_settings.cpp index e423ce38a..5f295404d 100644 --- a/src/core/hle/service/set/device_settings.cpp +++ b/src/core/hle/service/set/setting_formats/device_settings.cpp | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 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 "core/hle/service/set/device_settings.h" | 4 | #include "core/hle/service/set/setting_formats/device_settings.h" |
| 5 | 5 | ||
| 6 | namespace Service::Set { | 6 | namespace Service::Set { |
| 7 | 7 | ||
diff --git a/src/core/hle/service/set/device_settings.h b/src/core/hle/service/set/setting_formats/device_settings.h index f291d0ebe..2827756f6 100644 --- a/src/core/hle/service/set/device_settings.h +++ b/src/core/hle/service/set/setting_formats/device_settings.h | |||
| @@ -7,10 +7,12 @@ | |||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/vector_math.h" | ||
| 11 | #include "core/hle/service/set/settings_types.h" | ||
| 10 | 12 | ||
| 11 | namespace Service::Set { | 13 | namespace Service::Set { |
| 12 | struct DeviceSettings { | 14 | struct DeviceSettings { |
| 13 | std::array<u8, 0x10> reserved_000; | 15 | INSERT_PADDING_BYTES(0x10); // Reserved |
| 14 | 16 | ||
| 15 | // nn::settings::BatteryLot | 17 | // nn::settings::BatteryLot |
| 16 | std::array<u8, 0x18> ptm_battery_lot; | 18 | std::array<u8, 0x18> ptm_battery_lot; |
| @@ -19,26 +21,24 @@ struct DeviceSettings { | |||
| 19 | u8 ptm_battery_version; | 21 | u8 ptm_battery_version; |
| 20 | // nn::settings::system::PtmCycleCountReliability | 22 | // nn::settings::system::PtmCycleCountReliability |
| 21 | u32 ptm_cycle_count_reliability; | 23 | u32 ptm_cycle_count_reliability; |
| 22 | 24 | INSERT_PADDING_BYTES(0x48); // Reserved | |
| 23 | std::array<u8, 0x48> reserved_048; | ||
| 24 | 25 | ||
| 25 | // nn::settings::system::AnalogStickUserCalibration L | 26 | // nn::settings::system::AnalogStickUserCalibration L |
| 26 | std::array<u8, 0x10> analog_user_stick_calibration_l; | 27 | std::array<u8, 0x10> analog_user_stick_calibration_l; |
| 27 | // nn::settings::system::AnalogStickUserCalibration R | 28 | // nn::settings::system::AnalogStickUserCalibration R |
| 28 | std::array<u8, 0x10> analog_user_stick_calibration_r; | 29 | std::array<u8, 0x10> analog_user_stick_calibration_r; |
| 29 | 30 | INSERT_PADDING_BYTES(0x20); // Reserved | |
| 30 | std::array<u8, 0x20> reserved_0B0; | ||
| 31 | 31 | ||
| 32 | // nn::settings::system::ConsoleSixAxisSensorAccelerationBias | 32 | // nn::settings::system::ConsoleSixAxisSensorAccelerationBias |
| 33 | std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias; | 33 | Common::Vec3<f32> console_six_axis_sensor_acceleration_bias; |
| 34 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias | 34 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias |
| 35 | std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias; | 35 | Common::Vec3<f32> console_six_axis_sensor_angular_velocity_bias; |
| 36 | // nn::settings::system::ConsoleSixAxisSensorAccelerationGain | 36 | // nn::settings::system::ConsoleSixAxisSensorAccelerationGain |
| 37 | std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; | 37 | std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; |
| 38 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain | 38 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain |
| 39 | std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; | 39 | std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; |
| 40 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias | 40 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias |
| 41 | std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias; | 41 | Common::Vec3<f32> console_six_axis_sensor_angular_velocity_time_bias; |
| 42 | // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration | 42 | // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration |
| 43 | std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration; | 43 | std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration; |
| 44 | }; | 44 | }; |
diff --git a/src/core/hle/service/set/private_settings.cpp b/src/core/hle/service/set/setting_formats/private_settings.cpp index 70bf65727..81c362482 100644 --- a/src/core/hle/service/set/private_settings.cpp +++ b/src/core/hle/service/set/setting_formats/private_settings.cpp | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 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 "core/hle/service/set/private_settings.h" | 4 | #include "core/hle/service/set/setting_formats/private_settings.h" |
| 5 | 5 | ||
| 6 | namespace Service::Set { | 6 | namespace Service::Set { |
| 7 | 7 | ||
diff --git a/src/core/hle/service/set/setting_formats/private_settings.h b/src/core/hle/service/set/setting_formats/private_settings.h new file mode 100644 index 000000000..6c40f62e1 --- /dev/null +++ b/src/core/hle/service/set/setting_formats/private_settings.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/uuid.h" | ||
| 10 | #include "core/hle/service/set/settings_types.h" | ||
| 11 | #include "core/hle/service/time/clock_types.h" | ||
| 12 | |||
| 13 | namespace Service::Set { | ||
| 14 | |||
| 15 | struct PrivateSettings { | ||
| 16 | INSERT_PADDING_BYTES(0x10); // Reserved | ||
| 17 | |||
| 18 | InitialLaunchSettings initial_launch_settings; | ||
| 19 | INSERT_PADDING_BYTES(0x20); // Reserved | ||
| 20 | |||
| 21 | Common::UUID external_clock_source_id; | ||
| 22 | s64 shutdown_rtc_value; | ||
| 23 | s64 external_steady_clock_internal_offset; | ||
| 24 | INSERT_PADDING_BYTES(0x60); // Reserved | ||
| 25 | |||
| 26 | // nn::settings::system::PlatformRegion | ||
| 27 | s32 platform_region; | ||
| 28 | INSERT_PADDING_BYTES(0x4); // Reserved | ||
| 29 | }; | ||
| 30 | static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10); | ||
| 31 | static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50); | ||
| 32 | static_assert(offsetof(PrivateSettings, shutdown_rtc_value) == 0x60); | ||
| 33 | static_assert(offsetof(PrivateSettings, external_steady_clock_internal_offset) == 0x68); | ||
| 34 | static_assert(offsetof(PrivateSettings, platform_region) == 0xD0); | ||
| 35 | static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!"); | ||
| 36 | |||
| 37 | PrivateSettings DefaultPrivateSettings(); | ||
| 38 | |||
| 39 | } // namespace Service::Set | ||
diff --git a/src/core/hle/service/set/system_settings.cpp b/src/core/hle/service/set/setting_formats/system_settings.cpp index 5977429b2..66e57651e 100644 --- a/src/core/hle/service/set/system_settings.cpp +++ b/src/core/hle/service/set/setting_formats/system_settings.cpp | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2018 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 "core/hle/service/set/system_settings.h" | 4 | #include "core/hle/service/set/setting_formats/system_settings.h" |
| 5 | 5 | ||
| 6 | namespace Service::Set { | 6 | namespace Service::Set { |
| 7 | 7 | ||
| @@ -11,6 +11,8 @@ SystemSettings DefaultSystemSettings() { | |||
| 11 | settings.version = 0x140000; | 11 | settings.version = 0x140000; |
| 12 | settings.flags = 7; | 12 | settings.flags = 7; |
| 13 | 13 | ||
| 14 | settings.mii_author_id = Common::UUID::MakeDefault(); | ||
| 15 | |||
| 14 | settings.color_set_id = ColorSet::BasicWhite; | 16 | settings.color_set_id = ColorSet::BasicWhite; |
| 15 | 17 | ||
| 16 | settings.notification_settings = { | 18 | settings.notification_settings = { |
| @@ -45,6 +47,10 @@ SystemSettings DefaultSystemSettings() { | |||
| 45 | settings.device_time_zone_location_name = {"UTC"}; | 47 | settings.device_time_zone_location_name = {"UTC"}; |
| 46 | settings.user_system_clock_automatic_correction_enabled = false; | 48 | settings.user_system_clock_automatic_correction_enabled = false; |
| 47 | 49 | ||
| 50 | settings.primary_album_storage = PrimaryAlbumStorage::SdCard; | ||
| 51 | settings.battery_percentage_flag = true; | ||
| 52 | settings.chinese_traditional_input_method = ChineseTraditionalInputMethod::Unknown0; | ||
| 53 | |||
| 48 | return settings; | 54 | return settings; |
| 49 | } | 55 | } |
| 50 | 56 | ||
diff --git a/src/core/hle/service/set/system_settings.h b/src/core/hle/service/set/setting_formats/system_settings.h index 6ec9e71e7..14654f8b1 100644 --- a/src/core/hle/service/set/system_settings.h +++ b/src/core/hle/service/set/setting_formats/system_settings.h | |||
| @@ -8,272 +8,14 @@ | |||
| 8 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 9 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/service/set/private_settings.h" | 11 | #include "common/uuid.h" |
| 12 | #include "common/vector_math.h" | ||
| 13 | #include "core/hle/service/set/setting_formats/private_settings.h" | ||
| 14 | #include "core/hle/service/set/settings_types.h" | ||
| 12 | #include "core/hle/service/time/clock_types.h" | 15 | #include "core/hle/service/time/clock_types.h" |
| 13 | 16 | ||
| 14 | namespace Service::Set { | 17 | namespace Service::Set { |
| 15 | 18 | ||
| 16 | /// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. | ||
| 17 | enum class LanguageCode : u64 { | ||
| 18 | JA = 0x000000000000616A, | ||
| 19 | EN_US = 0x00000053552D6E65, | ||
| 20 | FR = 0x0000000000007266, | ||
| 21 | DE = 0x0000000000006564, | ||
| 22 | IT = 0x0000000000007469, | ||
| 23 | ES = 0x0000000000007365, | ||
| 24 | ZH_CN = 0x0000004E432D687A, | ||
| 25 | KO = 0x0000000000006F6B, | ||
| 26 | NL = 0x0000000000006C6E, | ||
| 27 | PT = 0x0000000000007470, | ||
| 28 | RU = 0x0000000000007572, | ||
| 29 | ZH_TW = 0x00000057542D687A, | ||
| 30 | EN_GB = 0x00000042472D6E65, | ||
| 31 | FR_CA = 0x00000041432D7266, | ||
| 32 | ES_419 = 0x00003931342D7365, | ||
| 33 | ZH_HANS = 0x00736E61482D687A, | ||
| 34 | ZH_HANT = 0x00746E61482D687A, | ||
| 35 | PT_BR = 0x00000052422D7470, | ||
| 36 | }; | ||
| 37 | |||
| 38 | /// This is nn::settings::system::ErrorReportSharePermission | ||
| 39 | enum class ErrorReportSharePermission : u32 { | ||
| 40 | NotConfirmed, | ||
| 41 | Granted, | ||
| 42 | Denied, | ||
| 43 | }; | ||
| 44 | |||
| 45 | /// This is nn::settings::system::ChineseTraditionalInputMethod | ||
| 46 | enum class ChineseTraditionalInputMethod : u32 { | ||
| 47 | Unknown0 = 0, | ||
| 48 | Unknown1 = 1, | ||
| 49 | Unknown2 = 2, | ||
| 50 | }; | ||
| 51 | |||
| 52 | /// This is nn::settings::system::HomeMenuScheme | ||
| 53 | struct HomeMenuScheme { | ||
| 54 | u32 main; | ||
| 55 | u32 back; | ||
| 56 | u32 sub; | ||
| 57 | u32 bezel; | ||
| 58 | u32 extra; | ||
| 59 | }; | ||
| 60 | static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size"); | ||
| 61 | |||
| 62 | /// Indicates the current theme set by the system settings | ||
| 63 | enum class ColorSet : u32 { | ||
| 64 | BasicWhite = 0, | ||
| 65 | BasicBlack = 1, | ||
| 66 | }; | ||
| 67 | |||
| 68 | /// Indicates the current console is a retail or kiosk unit | ||
| 69 | enum class QuestFlag : u8 { | ||
| 70 | Retail = 0, | ||
| 71 | Kiosk = 1, | ||
| 72 | }; | ||
| 73 | |||
| 74 | /// This is nn::settings::system::RegionCode | ||
| 75 | enum class RegionCode : u32 { | ||
| 76 | Japan, | ||
| 77 | Usa, | ||
| 78 | Europe, | ||
| 79 | Australia, | ||
| 80 | HongKongTaiwanKorea, | ||
| 81 | China, | ||
| 82 | }; | ||
| 83 | |||
| 84 | /// This is nn::settings::system::AccountSettings | ||
| 85 | struct AccountSettings { | ||
| 86 | u32 flags; | ||
| 87 | }; | ||
| 88 | static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size"); | ||
| 89 | |||
| 90 | /// This is nn::settings::system::NotificationVolume | ||
| 91 | enum class NotificationVolume : u32 { | ||
| 92 | Mute, | ||
| 93 | Low, | ||
| 94 | High, | ||
| 95 | }; | ||
| 96 | |||
| 97 | /// This is nn::settings::system::NotificationFlag | ||
| 98 | struct NotificationFlag { | ||
| 99 | union { | ||
| 100 | u32 raw{}; | ||
| 101 | |||
| 102 | BitField<0, 1, u32> RingtoneFlag; | ||
| 103 | BitField<1, 1, u32> DownloadCompletionFlag; | ||
| 104 | BitField<8, 1, u32> EnablesNews; | ||
| 105 | BitField<9, 1, u32> IncomingLampFlag; | ||
| 106 | }; | ||
| 107 | }; | ||
| 108 | static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size"); | ||
| 109 | |||
| 110 | /// This is nn::settings::system::NotificationTime | ||
| 111 | struct NotificationTime { | ||
| 112 | u32 hour; | ||
| 113 | u32 minute; | ||
| 114 | }; | ||
| 115 | static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size"); | ||
| 116 | |||
| 117 | /// This is nn::settings::system::NotificationSettings | ||
| 118 | struct NotificationSettings { | ||
| 119 | NotificationFlag flags; | ||
| 120 | NotificationVolume volume; | ||
| 121 | NotificationTime start_time; | ||
| 122 | NotificationTime stop_time; | ||
| 123 | }; | ||
| 124 | static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size"); | ||
| 125 | |||
| 126 | /// This is nn::settings::system::AccountNotificationFlag | ||
| 127 | struct AccountNotificationFlag { | ||
| 128 | union { | ||
| 129 | u32 raw{}; | ||
| 130 | |||
| 131 | BitField<0, 1, u32> FriendOnlineFlag; | ||
| 132 | BitField<1, 1, u32> FriendRequestFlag; | ||
| 133 | BitField<8, 1, u32> CoralInvitationFlag; | ||
| 134 | }; | ||
| 135 | }; | ||
| 136 | static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size"); | ||
| 137 | |||
| 138 | /// This is nn::settings::system::FriendPresenceOverlayPermission | ||
| 139 | enum class FriendPresenceOverlayPermission : u8 { | ||
| 140 | NotConfirmed, | ||
| 141 | NoDisplay, | ||
| 142 | FavoriteFriends, | ||
| 143 | Friends, | ||
| 144 | }; | ||
| 145 | |||
| 146 | /// This is nn::settings::system::AccountNotificationSettings | ||
| 147 | struct AccountNotificationSettings { | ||
| 148 | Common::UUID uid; | ||
| 149 | AccountNotificationFlag flags; | ||
| 150 | FriendPresenceOverlayPermission friend_presence_permission; | ||
| 151 | FriendPresenceOverlayPermission friend_invitation_permission; | ||
| 152 | INSERT_PADDING_BYTES(0x2); | ||
| 153 | }; | ||
| 154 | static_assert(sizeof(AccountNotificationSettings) == 0x18, | ||
| 155 | "AccountNotificationSettings is an invalid size"); | ||
| 156 | |||
| 157 | /// This is nn::settings::system::TvFlag | ||
| 158 | struct TvFlag { | ||
| 159 | union { | ||
| 160 | u32 raw{}; | ||
| 161 | |||
| 162 | BitField<0, 1, u32> Allows4k; | ||
| 163 | BitField<1, 1, u32> Allows3d; | ||
| 164 | BitField<2, 1, u32> AllowsCec; | ||
| 165 | BitField<3, 1, u32> PreventsScreenBurnIn; | ||
| 166 | }; | ||
| 167 | }; | ||
| 168 | static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size"); | ||
| 169 | |||
| 170 | /// This is nn::settings::system::TvResolution | ||
| 171 | enum class TvResolution : u32 { | ||
| 172 | Auto, | ||
| 173 | Resolution1080p, | ||
| 174 | Resolution720p, | ||
| 175 | Resolution480p, | ||
| 176 | }; | ||
| 177 | |||
| 178 | /// This is nn::settings::system::HdmiContentType | ||
| 179 | enum class HdmiContentType : u32 { | ||
| 180 | None, | ||
| 181 | Graphics, | ||
| 182 | Cinema, | ||
| 183 | Photo, | ||
| 184 | Game, | ||
| 185 | }; | ||
| 186 | |||
| 187 | /// This is nn::settings::system::RgbRange | ||
| 188 | enum class RgbRange : u32 { | ||
| 189 | Auto, | ||
| 190 | Full, | ||
| 191 | Limited, | ||
| 192 | }; | ||
| 193 | |||
| 194 | /// This is nn::settings::system::CmuMode | ||
| 195 | enum class CmuMode : u32 { | ||
| 196 | None, | ||
| 197 | ColorInvert, | ||
| 198 | HighContrast, | ||
| 199 | GrayScale, | ||
| 200 | }; | ||
| 201 | |||
| 202 | /// This is nn::settings::system::TvSettings | ||
| 203 | struct TvSettings { | ||
| 204 | TvFlag flags; | ||
| 205 | TvResolution tv_resolution; | ||
| 206 | HdmiContentType hdmi_content_type; | ||
| 207 | RgbRange rgb_range; | ||
| 208 | CmuMode cmu_mode; | ||
| 209 | u32 tv_underscan; | ||
| 210 | f32 tv_gama; | ||
| 211 | f32 contrast_ratio; | ||
| 212 | }; | ||
| 213 | static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); | ||
| 214 | |||
| 215 | /// This is nn::settings::system::PrimaryAlbumStorage | ||
| 216 | enum class PrimaryAlbumStorage : u32 { | ||
| 217 | Nand, | ||
| 218 | SdCard, | ||
| 219 | }; | ||
| 220 | |||
| 221 | /// This is nn::settings::system::HandheldSleepPlan | ||
| 222 | enum class HandheldSleepPlan : u32 { | ||
| 223 | Sleep1Min, | ||
| 224 | Sleep3Min, | ||
| 225 | Sleep5Min, | ||
| 226 | Sleep10Min, | ||
| 227 | Sleep30Min, | ||
| 228 | Never, | ||
| 229 | }; | ||
| 230 | |||
| 231 | /// This is nn::settings::system::ConsoleSleepPlan | ||
| 232 | enum class ConsoleSleepPlan : u32 { | ||
| 233 | Sleep1Hour, | ||
| 234 | Sleep2Hour, | ||
| 235 | Sleep3Hour, | ||
| 236 | Sleep6Hour, | ||
| 237 | Sleep12Hour, | ||
| 238 | Never, | ||
| 239 | }; | ||
| 240 | |||
| 241 | /// This is nn::settings::system::SleepFlag | ||
| 242 | struct SleepFlag { | ||
| 243 | union { | ||
| 244 | u32 raw{}; | ||
| 245 | |||
| 246 | BitField<0, 1, u32> SleepsWhilePlayingMedia; | ||
| 247 | BitField<1, 1, u32> WakesAtPowerStateChange; | ||
| 248 | }; | ||
| 249 | }; | ||
| 250 | static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size"); | ||
| 251 | |||
| 252 | /// This is nn::settings::system::SleepSettings | ||
| 253 | struct SleepSettings { | ||
| 254 | SleepFlag flags; | ||
| 255 | HandheldSleepPlan handheld_sleep_plan; | ||
| 256 | ConsoleSleepPlan console_sleep_plan; | ||
| 257 | }; | ||
| 258 | static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size"); | ||
| 259 | |||
| 260 | /// This is nn::settings::system::EulaVersionClockType | ||
| 261 | enum class EulaVersionClockType : u32 { | ||
| 262 | NetworkSystemClock, | ||
| 263 | SteadyClock, | ||
| 264 | }; | ||
| 265 | |||
| 266 | /// This is nn::settings::system::EulaVersion | ||
| 267 | struct EulaVersion { | ||
| 268 | u32 version; | ||
| 269 | RegionCode region_code; | ||
| 270 | EulaVersionClockType clock_type; | ||
| 271 | INSERT_PADDING_BYTES(0x4); | ||
| 272 | s64 posix_time; | ||
| 273 | Time::Clock::SteadyClockTimePoint timestamp; | ||
| 274 | }; | ||
| 275 | static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); | ||
| 276 | |||
| 277 | struct SystemSettings { | 19 | struct SystemSettings { |
| 278 | // 0/unwritten (1.0.0), 0x20000 (2.0.0), 0x30000 (3.0.0-3.0.1), 0x40001 (4.0.0-4.1.0), 0x50000 | 20 | // 0/unwritten (1.0.0), 0x20000 (2.0.0), 0x30000 (3.0.0-3.0.1), 0x40001 (4.0.0-4.1.0), 0x50000 |
| 279 | // (5.0.0-5.1.0), 0x60000 (6.0.0-6.2.0), 0x70000 (7.0.0), 0x80000 (8.0.0-8.1.1), 0x90000 | 21 | // (5.0.0-5.1.0), 0x60000 (6.0.0-6.2.0), 0x70000 (7.0.0), 0x80000 (8.0.0-8.1.1), 0x90000 |
| @@ -283,20 +25,16 @@ struct SystemSettings { | |||
| 283 | // 0/unwritten (1.0.0), 1 (6.0.0-8.1.0), 2 (8.1.1), 7 (9.0.0+). | 25 | // 0/unwritten (1.0.0), 1 (6.0.0-8.1.0), 2 (8.1.1), 7 (9.0.0+). |
| 284 | // if (flags & 2), defaults are written for AnalogStickUserCalibration | 26 | // if (flags & 2), defaults are written for AnalogStickUserCalibration |
| 285 | u32 flags; | 27 | u32 flags; |
| 28 | INSERT_PADDING_BYTES(0x8); // Reserved | ||
| 286 | 29 | ||
| 287 | std::array<u8, 0x8> reserved_00008; | ||
| 288 | |||
| 289 | // nn::settings::LanguageCode | ||
| 290 | LanguageCode language_code; | 30 | LanguageCode language_code; |
| 291 | 31 | INSERT_PADDING_BYTES(0x38); // Reserved | |
| 292 | std::array<u8, 0x38> reserved_00018; | ||
| 293 | 32 | ||
| 294 | // nn::settings::system::NetworkSettings | 33 | // nn::settings::system::NetworkSettings |
| 295 | u32 network_setting_count; | 34 | u32 network_setting_count; |
| 296 | bool wireless_lan_enable_flag; | 35 | bool wireless_lan_enable_flag; |
| 297 | std::array<u8, 0x3> pad_00055; | 36 | INSERT_PADDING_BYTES(0x3); |
| 298 | 37 | INSERT_PADDING_BYTES(0x8); // Reserved | |
| 299 | std::array<u8, 0x8> reserved_00058; | ||
| 300 | 38 | ||
| 301 | // nn::settings::system::NetworkSettings | 39 | // nn::settings::system::NetworkSettings |
| 302 | std::array<std::array<u8, 0x400>, 32> network_settings_1B0; | 40 | std::array<std::array<u8, 0x400>, 32> network_settings_1B0; |
| @@ -304,161 +42,142 @@ struct SystemSettings { | |||
| 304 | // nn::settings::system::BluetoothDevicesSettings | 42 | // nn::settings::system::BluetoothDevicesSettings |
| 305 | std::array<u8, 0x4> bluetooth_device_settings_count; | 43 | std::array<u8, 0x4> bluetooth_device_settings_count; |
| 306 | bool bluetooth_enable_flag; | 44 | bool bluetooth_enable_flag; |
| 307 | std::array<u8, 0x3> pad_08065; | 45 | INSERT_PADDING_BYTES(0x3); |
| 308 | bool bluetooth_afh_enable_flag; | 46 | bool bluetooth_afh_enable_flag; |
| 309 | std::array<u8, 0x3> pad_08069; | 47 | INSERT_PADDING_BYTES(0x3); |
| 310 | bool bluetooth_boost_enable_flag; | 48 | bool bluetooth_boost_enable_flag; |
| 311 | std::array<u8, 0x3> pad_0806D; | 49 | INSERT_PADDING_BYTES(0x3); |
| 312 | std::array<std::array<u8, 0x200>, 10> bluetooth_device_settings_first_10; | 50 | std::array<std::array<u8, 0x200>, 10> bluetooth_device_settings_first_10; |
| 313 | 51 | ||
| 314 | s32 ldn_channel; | 52 | s32 ldn_channel; |
| 315 | 53 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 316 | std::array<u8, 0x3C> reserved_09474; | ||
| 317 | 54 | ||
| 318 | // nn::util::Uuid MiiAuthorId | 55 | // nn::util::Uuid MiiAuthorId |
| 319 | std::array<u8, 0x10> mii_author_id; | 56 | Common::UUID mii_author_id; |
| 320 | 57 | ||
| 321 | std::array<u8, 0x30> reserved_094C0; | 58 | INSERT_PADDING_BYTES(0x30); // Reserved |
| 322 | 59 | ||
| 323 | // nn::settings::system::NxControllerSettings | 60 | // nn::settings::system::NxControllerSettings |
| 324 | u32 nx_controller_settings_count; | 61 | u32 nx_controller_settings_count; |
| 325 | 62 | ||
| 326 | std::array<u8, 0xC> reserved_094F4; | 63 | INSERT_PADDING_BYTES(0xC); // Reserved |
| 327 | 64 | ||
| 328 | // nn::settings::system::NxControllerSettings, | 65 | // nn::settings::system::NxControllerSettings, |
| 329 | // nn::settings::system::NxControllerLegacySettings on 13.0.0+ | 66 | // nn::settings::system::NxControllerLegacySettings on 13.0.0+ |
| 330 | std::array<std::array<u8, 0x40>, 10> nx_controller_legacy_settings; | 67 | std::array<std::array<u8, 0x40>, 10> nx_controller_legacy_settings; |
| 331 | 68 | INSERT_PADDING_BYTES(0x170); // Reserved | |
| 332 | std::array<u8, 0x170> reserved_09780; | ||
| 333 | 69 | ||
| 334 | bool external_rtc_reset_flag; | 70 | bool external_rtc_reset_flag; |
| 335 | std::array<u8, 0x3> pad_098F1; | 71 | INSERT_PADDING_BYTES(0x3); |
| 336 | 72 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 337 | std::array<u8, 0x3C> reserved_098F4; | ||
| 338 | 73 | ||
| 339 | s32 push_notification_activity_mode_on_sleep; | 74 | s32 push_notification_activity_mode_on_sleep; |
| 75 | INSERT_PADDING_BYTES(0x3C); // Reserved | ||
| 340 | 76 | ||
| 341 | std::array<u8, 0x3C> reserved_09934; | ||
| 342 | |||
| 343 | // nn::settings::system::ErrorReportSharePermission | ||
| 344 | ErrorReportSharePermission error_report_share_permission; | 77 | ErrorReportSharePermission error_report_share_permission; |
| 78 | INSERT_PADDING_BYTES(0x3C); // Reserved | ||
| 345 | 79 | ||
| 346 | std::array<u8, 0x3C> reserved_09974; | 80 | KeyboardLayout keyboard_layout; |
| 347 | 81 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 348 | // nn::settings::KeyboardLayout | ||
| 349 | std::array<u8, 0x4> keyboard_layout; | ||
| 350 | |||
| 351 | std::array<u8, 0x3C> reserved_099B4; | ||
| 352 | 82 | ||
| 353 | bool web_inspector_flag; | 83 | bool web_inspector_flag; |
| 354 | std::array<u8, 0x3> pad_099F1; | 84 | INSERT_PADDING_BYTES(0x3); |
| 355 | 85 | ||
| 356 | // nn::settings::system::AllowedSslHost | 86 | // nn::settings::system::AllowedSslHost |
| 357 | u32 allowed_ssl_host_count; | 87 | u32 allowed_ssl_host_count; |
| 358 | 88 | ||
| 359 | bool memory_usage_rate_flag; | 89 | bool memory_usage_rate_flag; |
| 360 | std::array<u8, 0x3> pad_099F9; | 90 | INSERT_PADDING_BYTES(0x3); |
| 361 | 91 | INSERT_PADDING_BYTES(0x34); // Reserved | |
| 362 | std::array<u8, 0x34> reserved_099FC; | ||
| 363 | 92 | ||
| 364 | // nn::settings::system::HostFsMountPoint | 93 | // nn::settings::system::HostFsMountPoint |
| 365 | std::array<u8, 0x100> host_fs_mount_point; | 94 | std::array<u8, 0x100> host_fs_mount_point; |
| 366 | 95 | ||
| 367 | // nn::settings::system::AllowedSslHost | 96 | // nn::settings::system::AllowedSslHost |
| 368 | std::array<std::array<u8, 0x100>, 8> allowed_ssl_hosts; | 97 | std::array<std::array<u8, 0x100>, 8> allowed_ssl_hosts; |
| 369 | 98 | INSERT_PADDING_BYTES(0x6C0); // Reserved | |
| 370 | std::array<u8, 0x6C0> reserved_0A330; | ||
| 371 | 99 | ||
| 372 | // nn::settings::system::BlePairingSettings | 100 | // nn::settings::system::BlePairingSettings |
| 373 | u32 ble_pairing_settings_count; | 101 | u32 ble_pairing_settings_count; |
| 374 | std::array<u8, 0xC> reserved_0A9F4; | 102 | INSERT_PADDING_BYTES(0xC); // Reserved |
| 375 | std::array<std::array<u8, 0x80>, 10> ble_pairing_settings; | 103 | std::array<std::array<u8, 0x80>, 10> ble_pairing_settings; |
| 376 | 104 | ||
| 377 | // nn::settings::system::AccountOnlineStorageSettings | 105 | // nn::settings::system::AccountOnlineStorageSettings |
| 378 | u32 account_online_storage_settings_count; | 106 | u32 account_online_storage_settings_count; |
| 379 | std::array<u8, 0xC> reserved_0AF04; | 107 | INSERT_PADDING_BYTES(0xC); // Reserved |
| 380 | std::array<std::array<u8, 0x40>, 8> account_online_storage_settings; | 108 | std::array<std::array<u8, 0x40>, 8> account_online_storage_settings; |
| 381 | 109 | ||
| 382 | bool pctl_ready_flag; | 110 | bool pctl_ready_flag; |
| 383 | std::array<u8, 0x3> pad_0B111; | 111 | INSERT_PADDING_BYTES(0x3); |
| 384 | 112 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 385 | std::array<u8, 0x3C> reserved_0B114; | ||
| 386 | 113 | ||
| 387 | // nn::settings::system::ThemeId | 114 | // nn::settings::system::ThemeId |
| 388 | std::array<u8, 0x80> theme_id_type0; | 115 | std::array<u8, 0x80> theme_id_type0; |
| 389 | std::array<u8, 0x80> theme_id_type1; | 116 | std::array<u8, 0x80> theme_id_type1; |
| 117 | INSERT_PADDING_BYTES(0x100); // Reserved | ||
| 390 | 118 | ||
| 391 | std::array<u8, 0x100> reserved_0B250; | ||
| 392 | |||
| 393 | // nn::settings::ChineseTraditionalInputMethod | ||
| 394 | ChineseTraditionalInputMethod chinese_traditional_input_method; | 119 | ChineseTraditionalInputMethod chinese_traditional_input_method; |
| 395 | 120 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 396 | std::array<u8, 0x3C> reserved_0B354; | ||
| 397 | 121 | ||
| 398 | bool zoom_flag; | 122 | bool zoom_flag; |
| 399 | std::array<u8, 0x3> pad_0B391; | 123 | INSERT_PADDING_BYTES(0x3); |
| 400 | 124 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 401 | std::array<u8, 0x3C> reserved_0B394; | ||
| 402 | 125 | ||
| 403 | // nn::settings::system::ButtonConfigRegisteredSettings | 126 | // nn::settings::system::ButtonConfigRegisteredSettings |
| 404 | u32 button_config_registered_settings_count; | 127 | u32 button_config_registered_settings_count; |
| 405 | std::array<u8, 0xC> reserved_0B3D4; | 128 | INSERT_PADDING_BYTES(0xC); // Reserved |
| 406 | 129 | ||
| 407 | // nn::settings::system::ButtonConfigSettings | 130 | // nn::settings::system::ButtonConfigSettings |
| 408 | u32 button_config_settings_count; | 131 | u32 button_config_settings_count; |
| 409 | std::array<u8, 0x4> reserved_0B3E4; | 132 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 410 | std::array<std::array<u8, 0x5A8>, 5> button_config_settings; | 133 | std::array<std::array<u8, 0x5A8>, 5> button_config_settings; |
| 411 | std::array<u8, 0x13B0> reserved_0D030; | 134 | INSERT_PADDING_BYTES(0x13B0); // Reserved |
| 412 | u32 button_config_settings_embedded_count; | 135 | u32 button_config_settings_embedded_count; |
| 413 | std::array<u8, 0x4> reserved_0E3E4; | 136 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 414 | std::array<std::array<u8, 0x5A8>, 5> button_config_settings_embedded; | 137 | std::array<std::array<u8, 0x5A8>, 5> button_config_settings_embedded; |
| 415 | std::array<u8, 0x13B0> reserved_10030; | 138 | INSERT_PADDING_BYTES(0x13B0); // Reserved |
| 416 | u32 button_config_settings_left_count; | 139 | u32 button_config_settings_left_count; |
| 417 | std::array<u8, 0x4> reserved_113E4; | 140 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 418 | std::array<std::array<u8, 0x5A8>, 5> button_config_settings_left; | 141 | std::array<std::array<u8, 0x5A8>, 5> button_config_settings_left; |
| 419 | std::array<u8, 0x13B0> reserved_13030; | 142 | INSERT_PADDING_BYTES(0x13B0); // Reserved |
| 420 | u32 button_config_settings_right_count; | 143 | u32 button_config_settings_right_count; |
| 421 | std::array<u8, 0x4> reserved_143E4; | 144 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 422 | std::array<std::array<u8, 0x5A8>, 5> button_config_settings_right; | 145 | std::array<std::array<u8, 0x5A8>, 5> button_config_settings_right; |
| 423 | std::array<u8, 0x73B0> reserved_16030; | 146 | INSERT_PADDING_BYTES(0x73B0); // Reserved |
| 424 | // nn::settings::system::ButtonConfigRegisteredSettings | 147 | // nn::settings::system::ButtonConfigRegisteredSettings |
| 425 | std::array<u8, 0x5C8> button_config_registered_settings_embedded; | 148 | std::array<u8, 0x5C8> button_config_registered_settings_embedded; |
| 426 | std::array<std::array<u8, 0x5C8>, 10> button_config_registered_settings; | 149 | std::array<std::array<u8, 0x5C8>, 10> button_config_registered_settings; |
| 427 | 150 | INSERT_PADDING_BYTES(0x7FF8); // Reserved | |
| 428 | std::array<u8, 0x7FF8> reserved_21378; | ||
| 429 | 151 | ||
| 430 | // nn::settings::system::ConsoleSixAxisSensorAccelerationBias | 152 | // nn::settings::system::ConsoleSixAxisSensorAccelerationBias |
| 431 | std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias; | 153 | Common::Vec3<f32> console_six_axis_sensor_acceleration_bias; |
| 432 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias | 154 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias |
| 433 | std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias; | 155 | Common::Vec3<f32> console_six_axis_sensor_angular_velocity_bias; |
| 434 | // nn::settings::system::ConsoleSixAxisSensorAccelerationGain | 156 | // nn::settings::system::ConsoleSixAxisSensorAccelerationGain |
| 435 | std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; | 157 | std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; |
| 436 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain | 158 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain |
| 437 | std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; | 159 | std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; |
| 438 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias | 160 | // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias |
| 439 | std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias; | 161 | Common::Vec3<f32> console_six_axis_sensor_angular_velocity_time_bias; |
| 440 | // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration | 162 | // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration |
| 441 | std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration; | 163 | std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration; |
| 442 | 164 | INSERT_PADDING_BYTES(0x70); // Reserved | |
| 443 | std::array<u8, 0x70> reserved_29400; | ||
| 444 | 165 | ||
| 445 | bool lock_screen_flag; | 166 | bool lock_screen_flag; |
| 446 | std::array<u8, 0x3> pad_29471; | 167 | INSERT_PADDING_BYTES(0x3); |
| 447 | 168 | INSERT_PADDING_BYTES(0x4); // Reserved | |
| 448 | std::array<u8, 0x4> reserved_249274; | ||
| 449 | 169 | ||
| 450 | ColorSet color_set_id; | 170 | ColorSet color_set_id; |
| 451 | 171 | ||
| 452 | QuestFlag quest_flag; | 172 | QuestFlag quest_flag; |
| 453 | 173 | ||
| 454 | // nn::settings::system::RegionCode | 174 | SystemRegionCode region_code; |
| 455 | RegionCode region_code; | ||
| 456 | 175 | ||
| 457 | // Different to nn::settings::system::InitialLaunchSettings? | 176 | // Different to nn::settings::system::InitialLaunchSettings? |
| 458 | InitialLaunchSettingsPacked initial_launch_settings_packed; | 177 | InitialLaunchSettingsPacked initial_launch_settings_packed; |
| 459 | 178 | ||
| 460 | bool battery_percentage_flag; | 179 | bool battery_percentage_flag; |
| 461 | std::array<u8, 0x3> pad_294A1; | 180 | INSERT_PADDING_BYTES(0x3); |
| 462 | 181 | ||
| 463 | // BitFlagSet<32, nn::settings::system::AppletLaunchFlag> | 182 | // BitFlagSet<32, nn::settings::system::AppletLaunchFlag> |
| 464 | u32 applet_launch_flag; | 183 | u32 applet_launch_flag; |
| @@ -469,33 +188,26 @@ struct SystemSettings { | |||
| 469 | std::array<u8, 0x10> theme_key; | 188 | std::array<u8, 0x10> theme_key; |
| 470 | 189 | ||
| 471 | bool field_testing_flag; | 190 | bool field_testing_flag; |
| 472 | std::array<u8, 0x3> pad_294C1; | 191 | INSERT_PADDING_BYTES(0x3); |
| 473 | 192 | ||
| 474 | s32 panel_crc_mode; | 193 | s32 panel_crc_mode; |
| 475 | 194 | INSERT_PADDING_BYTES(0x28); // Reserved | |
| 476 | std::array<u8, 0x28> reserved_294C8; | ||
| 477 | 195 | ||
| 478 | // nn::settings::system::BacklightSettings | 196 | // nn::settings::system::BacklightSettings |
| 479 | std::array<u8, 0x2C> backlight_settings_mixed_up; | 197 | std::array<u8, 0x2C> backlight_settings_mixed_up; |
| 198 | INSERT_PADDING_BYTES(0x64); // Reserved | ||
| 480 | 199 | ||
| 481 | std::array<u8, 0x64> reserved_2951C; | ||
| 482 | |||
| 483 | // nn::time::SystemClockContext | ||
| 484 | Service::Time::Clock::SystemClockContext user_system_clock_context; | 200 | Service::Time::Clock::SystemClockContext user_system_clock_context; |
| 485 | Service::Time::Clock::SystemClockContext network_system_clock_context; | 201 | Service::Time::Clock::SystemClockContext network_system_clock_context; |
| 486 | bool user_system_clock_automatic_correction_enabled; | 202 | bool user_system_clock_automatic_correction_enabled; |
| 487 | std::array<u8, 0x3> pad_295C1; | 203 | INSERT_PADDING_BYTES(0x3); |
| 488 | std::array<u8, 0x4> reserved_295C4; | 204 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 489 | // nn::time::SteadyClockTimePoint | ||
| 490 | Service::Time::Clock::SteadyClockTimePoint | 205 | Service::Time::Clock::SteadyClockTimePoint |
| 491 | user_system_clock_automatic_correction_updated_time_point; | 206 | user_system_clock_automatic_correction_updated_time_point; |
| 207 | INSERT_PADDING_BYTES(0x10); // Reserved | ||
| 492 | 208 | ||
| 493 | std::array<u8, 0x10> reserved_295E0; | ||
| 494 | |||
| 495 | // nn::settings::system::AccountSettings | ||
| 496 | AccountSettings account_settings; | 209 | AccountSettings account_settings; |
| 497 | 210 | INSERT_PADDING_BYTES(0xFC); // Reserved | |
| 498 | std::array<u8, 0xFC> reserved_295F4; | ||
| 499 | 211 | ||
| 500 | // nn::settings::system::AudioVolume | 212 | // nn::settings::system::AudioVolume |
| 501 | std::array<u8, 0x8> audio_volume_type0; | 213 | std::array<u8, 0x8> audio_volume_type0; |
| @@ -505,47 +217,42 @@ struct SystemSettings { | |||
| 505 | s32 audio_output_mode_type1; | 217 | s32 audio_output_mode_type1; |
| 506 | s32 audio_output_mode_type2; | 218 | s32 audio_output_mode_type2; |
| 507 | bool force_mute_on_headphone_removed; | 219 | bool force_mute_on_headphone_removed; |
| 508 | std::array<u8, 0x3> pad_2970D; | 220 | INSERT_PADDING_BYTES(0x3); |
| 509 | s32 headphone_volume_warning_count; | 221 | s32 headphone_volume_warning_count; |
| 510 | bool heaphone_volume_update_flag; | 222 | bool heaphone_volume_update_flag; |
| 511 | std::array<u8, 0x3> pad_29715; | 223 | INSERT_PADDING_BYTES(0x3); |
| 512 | // nn::settings::system::AudioVolume | 224 | // nn::settings::system::AudioVolume |
| 513 | std::array<u8, 0x8> audio_volume_type2; | 225 | std::array<u8, 0x8> audio_volume_type2; |
| 514 | // nn::settings::system::AudioOutputMode | 226 | // nn::settings::system::AudioOutputMode |
| 515 | s32 audio_output_mode_type3; | 227 | s32 audio_output_mode_type3; |
| 516 | s32 audio_output_mode_type4; | 228 | s32 audio_output_mode_type4; |
| 517 | bool hearing_protection_safeguard_flag; | 229 | bool hearing_protection_safeguard_flag; |
| 518 | std::array<u8, 0x3> pad_29729; | 230 | INSERT_PADDING_BYTES(0x3); |
| 519 | std::array<u8, 0x4> reserved_2972C; | 231 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 520 | s64 hearing_protection_safeguard_remaining_time; | 232 | s64 hearing_protection_safeguard_remaining_time; |
| 521 | std::array<u8, 0x38> reserved_29738; | 233 | INSERT_PADDING_BYTES(0x38); // Reserved |
| 522 | 234 | ||
| 523 | bool console_information_upload_flag; | 235 | bool console_information_upload_flag; |
| 524 | std::array<u8, 0x3> pad_29771; | 236 | INSERT_PADDING_BYTES(0x3); |
| 525 | 237 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 526 | std::array<u8, 0x3C> reserved_29774; | ||
| 527 | 238 | ||
| 528 | bool automatic_application_download_flag; | 239 | bool automatic_application_download_flag; |
| 529 | std::array<u8, 0x3> pad_297B1; | 240 | INSERT_PADDING_BYTES(0x3); |
| 530 | 241 | INSERT_PADDING_BYTES(0x4); // Reserved | |
| 531 | std::array<u8, 0x4> reserved_297B4; | ||
| 532 | 242 | ||
| 533 | // nn::settings::system::NotificationSettings | ||
| 534 | NotificationSettings notification_settings; | 243 | NotificationSettings notification_settings; |
| 535 | 244 | INSERT_PADDING_BYTES(0x60); // Reserved | |
| 536 | std::array<u8, 0x60> reserved_297D0; | ||
| 537 | 245 | ||
| 538 | // nn::settings::system::AccountNotificationSettings | 246 | // nn::settings::system::AccountNotificationSettings |
| 539 | u32 account_notification_settings_count; | 247 | u32 account_notification_settings_count; |
| 540 | std::array<u8, 0xC> reserved_29834; | 248 | INSERT_PADDING_BYTES(0xC); // Reserved |
| 541 | std::array<AccountNotificationSettings, 8> account_notification_settings; | 249 | std::array<AccountNotificationSettings, 8> account_notification_settings; |
| 542 | 250 | INSERT_PADDING_BYTES(0x140); // Reserved | |
| 543 | std::array<u8, 0x140> reserved_29900; | ||
| 544 | 251 | ||
| 545 | f32 vibration_master_volume; | 252 | f32 vibration_master_volume; |
| 546 | 253 | ||
| 547 | bool usb_full_key_enable_flag; | 254 | bool usb_full_key_enable_flag; |
| 548 | std::array<u8, 0x3> pad_29A45; | 255 | INSERT_PADDING_BYTES(0x3); |
| 549 | 256 | ||
| 550 | // nn::settings::system::AnalogStickUserCalibration | 257 | // nn::settings::system::AnalogStickUserCalibration |
| 551 | std::array<u8, 0x10> analog_stick_user_calibration_left; | 258 | std::array<u8, 0x10> analog_stick_user_calibration_left; |
| @@ -553,85 +260,68 @@ struct SystemSettings { | |||
| 553 | 260 | ||
| 554 | // nn::settings::system::TouchScreenMode | 261 | // nn::settings::system::TouchScreenMode |
| 555 | s32 touch_screen_mode; | 262 | s32 touch_screen_mode; |
| 263 | INSERT_PADDING_BYTES(0x14); // Reserved | ||
| 556 | 264 | ||
| 557 | std::array<u8, 0x14> reserved_29A6C; | ||
| 558 | |||
| 559 | // nn::settings::system::TvSettings | ||
| 560 | TvSettings tv_settings; | 265 | TvSettings tv_settings; |
| 561 | 266 | ||
| 562 | // nn::settings::system::Edid | 267 | // nn::settings::system::Edid |
| 563 | std::array<u8, 0x100> edid; | 268 | std::array<u8, 0x100> edid; |
| 564 | 269 | INSERT_PADDING_BYTES(0x2E0); // Reserved | |
| 565 | std::array<u8, 0x2E0> reserved_29BA0; | ||
| 566 | 270 | ||
| 567 | // nn::settings::system::DataDeletionSettings | 271 | // nn::settings::system::DataDeletionSettings |
| 568 | std::array<u8, 0x8> data_deletion_settings; | 272 | std::array<u8, 0x8> data_deletion_settings; |
| 569 | 273 | INSERT_PADDING_BYTES(0x38); // Reserved | |
| 570 | std::array<u8, 0x38> reserved_29E88; | ||
| 571 | 274 | ||
| 572 | // nn::ncm::ProgramId | 275 | // nn::ncm::ProgramId |
| 573 | std::array<u8, 0x8> initial_system_applet_program_id; | 276 | std::array<u8, 0x8> initial_system_applet_program_id; |
| 574 | std::array<u8, 0x8> overlay_disp_program_id; | 277 | std::array<u8, 0x8> overlay_disp_program_id; |
| 575 | 278 | INSERT_PADDING_BYTES(0x4); // Reserved | |
| 576 | std::array<u8, 0x4> reserved_29ED0; | ||
| 577 | 279 | ||
| 578 | bool requires_run_repair_time_reviser; | 280 | bool requires_run_repair_time_reviser; |
| 281 | INSERT_PADDING_BYTES(0x6B); // Reserved | ||
| 579 | 282 | ||
| 580 | std::array<u8, 0x6B> reserved_29ED5; | ||
| 581 | |||
| 582 | // nn::time::LocationName | ||
| 583 | Service::Time::TimeZone::LocationName device_time_zone_location_name; | 283 | Service::Time::TimeZone::LocationName device_time_zone_location_name; |
| 584 | std::array<u8, 0x4> reserved_29F64; | 284 | INSERT_PADDING_BYTES(0x4); // Reserved |
| 585 | // nn::time::SteadyClockTimePoint | ||
| 586 | Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time; | 285 | Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time; |
| 587 | 286 | INSERT_PADDING_BYTES(0xC0); // Reserved | |
| 588 | std::array<u8, 0xC0> reserved_29F80; | ||
| 589 | 287 | ||
| 590 | // nn::settings::system::PrimaryAlbumStorage | 288 | // nn::settings::system::PrimaryAlbumStorage |
| 591 | PrimaryAlbumStorage primary_album_storage; | 289 | PrimaryAlbumStorage primary_album_storage; |
| 592 | 290 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 593 | std::array<u8, 0x3C> reserved_2A044; | ||
| 594 | 291 | ||
| 595 | bool usb_30_enable_flag; | 292 | bool usb_30_enable_flag; |
| 596 | std::array<u8, 0x3> pad_2A081; | 293 | INSERT_PADDING_BYTES(0x3); |
| 597 | bool usb_30_host_enable_flag; | 294 | bool usb_30_host_enable_flag; |
| 598 | std::array<u8, 0x3> pad_2A085; | 295 | INSERT_PADDING_BYTES(0x3); |
| 599 | bool usb_30_device_enable_flag; | 296 | bool usb_30_device_enable_flag; |
| 600 | std::array<u8, 0x3> pad_2A089; | 297 | INSERT_PADDING_BYTES(0x3); |
| 601 | 298 | INSERT_PADDING_BYTES(0x34); // Reserved | |
| 602 | std::array<u8, 0x34> reserved_2A08C; | ||
| 603 | 299 | ||
| 604 | bool nfc_enable_flag; | 300 | bool nfc_enable_flag; |
| 605 | std::array<u8, 0x3> pad_2A0C1; | 301 | INSERT_PADDING_BYTES(0x3); |
| 606 | 302 | INSERT_PADDING_BYTES(0x3C); // Reserved | |
| 607 | std::array<u8, 0x3C> reserved_2A0C4; | ||
| 608 | 303 | ||
| 609 | // nn::settings::system::SleepSettings | 304 | // nn::settings::system::SleepSettings |
| 610 | SleepSettings sleep_settings; | 305 | SleepSettings sleep_settings; |
| 611 | 306 | INSERT_PADDING_BYTES(0x34); // Reserved | |
| 612 | std::array<u8, 0x34> reserved_2A10C; | ||
| 613 | 307 | ||
| 614 | // nn::settings::system::EulaVersion | 308 | // nn::settings::system::EulaVersion |
| 615 | u32 eula_version_count; | 309 | u32 eula_version_count; |
| 616 | std::array<u8, 0xC> reserved_2A144; | 310 | INSERT_PADDING_BYTES(0xC); // Reserved |
| 617 | std::array<EulaVersion, 32> eula_versions; | 311 | std::array<EulaVersion, 32> eula_versions; |
| 618 | 312 | INSERT_PADDING_BYTES(0x200); // Reserved | |
| 619 | std::array<u8, 0x200> reserved_2A750; | ||
| 620 | 313 | ||
| 621 | // nn::settings::system::DeviceNickName | 314 | // nn::settings::system::DeviceNickName |
| 622 | std::array<u8, 0x80> device_nick_name; | 315 | std::array<u8, 0x80> device_nick_name; |
| 623 | 316 | INSERT_PADDING_BYTES(0x80); // Reserved | |
| 624 | std::array<u8, 0x80> reserved_2A9D0; | ||
| 625 | 317 | ||
| 626 | bool auto_update_enable_flag; | 318 | bool auto_update_enable_flag; |
| 627 | std::array<u8, 0x3> pad_2AA51; | 319 | INSERT_PADDING_BYTES(0x3); |
| 628 | 320 | INSERT_PADDING_BYTES(0x4C); // Reserved | |
| 629 | std::array<u8, 0x4C> reserved_2AA54; | ||
| 630 | 321 | ||
| 631 | // nn::settings::system::BluetoothDevicesSettings | 322 | // nn::settings::system::BluetoothDevicesSettings |
| 632 | std::array<std::array<u8, 0x200>, 14> bluetooth_device_settings_last_14; | 323 | std::array<std::array<u8, 0x200>, 14> bluetooth_device_settings_last_14; |
| 633 | 324 | INSERT_PADDING_BYTES(0x2000); // Reserved | |
| 634 | std::array<u8, 0x2000> reserved_2C6A0; | ||
| 635 | 325 | ||
| 636 | // nn::settings::system::NxControllerSettings | 326 | // nn::settings::system::NxControllerSettings |
| 637 | std::array<std::array<u8, 0x800>, 10> nx_controller_settings_data_from_offset_30; | 327 | std::array<std::array<u8, 0x800>, 10> nx_controller_settings_data_from_offset_30; |
diff --git a/src/core/hle/service/set/settings_server.h b/src/core/hle/service/set/settings_server.h index a4e78db6c..8304e8424 100644 --- a/src/core/hle/service/set/settings_server.h +++ b/src/core/hle/service/set/settings_server.h | |||
| @@ -4,72 +4,13 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "core/hle/service/service.h" | 6 | #include "core/hle/service/service.h" |
| 7 | #include "core/hle/service/set/system_settings.h" | 7 | #include "core/hle/service/set/settings_types.h" |
| 8 | 8 | ||
| 9 | namespace Core { | 9 | namespace Core { |
| 10 | class System; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Service::Set { | 13 | namespace Service::Set { |
| 14 | enum class KeyboardLayout : u64 { | ||
| 15 | Japanese = 0, | ||
| 16 | EnglishUs = 1, | ||
| 17 | EnglishUsInternational = 2, | ||
| 18 | EnglishUk = 3, | ||
| 19 | French = 4, | ||
| 20 | FrenchCa = 5, | ||
| 21 | Spanish = 6, | ||
| 22 | SpanishLatin = 7, | ||
| 23 | German = 8, | ||
| 24 | Italian = 9, | ||
| 25 | Portuguese = 10, | ||
| 26 | Russian = 11, | ||
| 27 | Korean = 12, | ||
| 28 | ChineseSimplified = 13, | ||
| 29 | ChineseTraditional = 14, | ||
| 30 | }; | ||
| 31 | |||
| 32 | constexpr std::array<LanguageCode, 18> available_language_codes = {{ | ||
| 33 | LanguageCode::JA, | ||
| 34 | LanguageCode::EN_US, | ||
| 35 | LanguageCode::FR, | ||
| 36 | LanguageCode::DE, | ||
| 37 | LanguageCode::IT, | ||
| 38 | LanguageCode::ES, | ||
| 39 | LanguageCode::ZH_CN, | ||
| 40 | LanguageCode::KO, | ||
| 41 | LanguageCode::NL, | ||
| 42 | LanguageCode::PT, | ||
| 43 | LanguageCode::RU, | ||
| 44 | LanguageCode::ZH_TW, | ||
| 45 | LanguageCode::EN_GB, | ||
| 46 | LanguageCode::FR_CA, | ||
| 47 | LanguageCode::ES_419, | ||
| 48 | LanguageCode::ZH_HANS, | ||
| 49 | LanguageCode::ZH_HANT, | ||
| 50 | LanguageCode::PT_BR, | ||
| 51 | }}; | ||
| 52 | |||
| 53 | static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{ | ||
| 54 | {LanguageCode::JA, KeyboardLayout::Japanese}, | ||
| 55 | {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, | ||
| 56 | {LanguageCode::FR, KeyboardLayout::French}, | ||
| 57 | {LanguageCode::DE, KeyboardLayout::German}, | ||
| 58 | {LanguageCode::IT, KeyboardLayout::Italian}, | ||
| 59 | {LanguageCode::ES, KeyboardLayout::Spanish}, | ||
| 60 | {LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified}, | ||
| 61 | {LanguageCode::KO, KeyboardLayout::Korean}, | ||
| 62 | {LanguageCode::NL, KeyboardLayout::EnglishUsInternational}, | ||
| 63 | {LanguageCode::PT, KeyboardLayout::Portuguese}, | ||
| 64 | {LanguageCode::RU, KeyboardLayout::Russian}, | ||
| 65 | {LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional}, | ||
| 66 | {LanguageCode::EN_GB, KeyboardLayout::EnglishUk}, | ||
| 67 | {LanguageCode::FR_CA, KeyboardLayout::FrenchCa}, | ||
| 68 | {LanguageCode::ES_419, KeyboardLayout::SpanishLatin}, | ||
| 69 | {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, | ||
| 70 | {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, | ||
| 71 | {LanguageCode::PT_BR, KeyboardLayout::Portuguese}, | ||
| 72 | }}; | ||
| 73 | 14 | ||
| 74 | LanguageCode GetLanguageCodeFromIndex(std::size_t idx); | 15 | LanguageCode GetLanguageCodeFromIndex(std::size_t idx); |
| 75 | 16 | ||
diff --git a/src/core/hle/service/set/settings_types.h b/src/core/hle/service/set/settings_types.h new file mode 100644 index 000000000..4dee202d7 --- /dev/null +++ b/src/core/hle/service/set/settings_types.h | |||
| @@ -0,0 +1,451 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | |||
| 8 | #include "common/bit_field.h" | ||
| 9 | #include "common/common_funcs.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/uuid.h" | ||
| 12 | #include "core/hle/service/time/clock_types.h" | ||
| 13 | |||
| 14 | namespace Service::Set { | ||
| 15 | |||
| 16 | /// This is nn::settings::system::AudioOutputMode | ||
| 17 | enum class AudioOutputMode : u32 { | ||
| 18 | ch_1, | ||
| 19 | ch_2, | ||
| 20 | ch_5_1, | ||
| 21 | ch_7_1, | ||
| 22 | }; | ||
| 23 | |||
| 24 | /// This is nn::settings::system::AudioOutputModeTarget | ||
| 25 | enum class AudioOutputModeTarget : u32 { | ||
| 26 | Hdmi, | ||
| 27 | Speaker, | ||
| 28 | Headphone, | ||
| 29 | }; | ||
| 30 | |||
| 31 | /// This is nn::settings::system::AudioVolumeTarget | ||
| 32 | enum class AudioVolumeTarget : u32 { | ||
| 33 | Speaker, | ||
| 34 | Headphone, | ||
| 35 | }; | ||
| 36 | |||
| 37 | /// This is nn::settings::system::ClockSourceId | ||
| 38 | enum class ClockSourceId : u32 { | ||
| 39 | NetworkSystemClock, | ||
| 40 | SteadyClock, | ||
| 41 | }; | ||
| 42 | |||
| 43 | /// This is nn::settings::system::CmuMode | ||
| 44 | enum class CmuMode : u32 { | ||
| 45 | None, | ||
| 46 | ColorInvert, | ||
| 47 | HighContrast, | ||
| 48 | GrayScale, | ||
| 49 | }; | ||
| 50 | |||
| 51 | /// This is nn::settings::system::ChineseTraditionalInputMethod | ||
| 52 | enum class ChineseTraditionalInputMethod : u32 { | ||
| 53 | Unknown0 = 0, | ||
| 54 | Unknown1 = 1, | ||
| 55 | Unknown2 = 2, | ||
| 56 | }; | ||
| 57 | |||
| 58 | /// Indicates the current theme set by the system settings | ||
| 59 | enum class ColorSet : u32 { | ||
| 60 | BasicWhite = 0, | ||
| 61 | BasicBlack = 1, | ||
| 62 | }; | ||
| 63 | |||
| 64 | /// This is nn::settings::system::ConsoleSleepPlan | ||
| 65 | enum class ConsoleSleepPlan : u32 { | ||
| 66 | Sleep1Hour, | ||
| 67 | Sleep2Hour, | ||
| 68 | Sleep3Hour, | ||
| 69 | Sleep6Hour, | ||
| 70 | Sleep12Hour, | ||
| 71 | Never, | ||
| 72 | }; | ||
| 73 | |||
| 74 | /// This is nn::settings::system::ErrorReportSharePermission | ||
| 75 | enum class ErrorReportSharePermission : u32 { | ||
| 76 | NotConfirmed, | ||
| 77 | Granted, | ||
| 78 | Denied, | ||
| 79 | }; | ||
| 80 | |||
| 81 | /// This is nn::settings::system::EulaVersionClockType | ||
| 82 | enum class EulaVersionClockType : u32 { | ||
| 83 | NetworkSystemClock, | ||
| 84 | SteadyClock, | ||
| 85 | }; | ||
| 86 | |||
| 87 | /// This is nn::settings::factory::RegionCode | ||
| 88 | enum class FactoryRegionCode : u32 { | ||
| 89 | Japan, | ||
| 90 | Usa, | ||
| 91 | Europe, | ||
| 92 | Australia, | ||
| 93 | China, | ||
| 94 | Korea, | ||
| 95 | Taiwan, | ||
| 96 | }; | ||
| 97 | |||
| 98 | /// This is nn::settings::system::FriendPresenceOverlayPermission | ||
| 99 | enum class FriendPresenceOverlayPermission : u8 { | ||
| 100 | NotConfirmed, | ||
| 101 | NoDisplay, | ||
| 102 | FavoriteFriends, | ||
| 103 | Friends, | ||
| 104 | }; | ||
| 105 | |||
| 106 | enum class GetFirmwareVersionType { | ||
| 107 | Version1, | ||
| 108 | Version2, | ||
| 109 | }; | ||
| 110 | |||
| 111 | /// This is nn::settings::system::HandheldSleepPlan | ||
| 112 | enum class HandheldSleepPlan : u32 { | ||
| 113 | Sleep1Min, | ||
| 114 | Sleep3Min, | ||
| 115 | Sleep5Min, | ||
| 116 | Sleep10Min, | ||
| 117 | Sleep30Min, | ||
| 118 | Never, | ||
| 119 | }; | ||
| 120 | |||
| 121 | /// This is nn::settings::system::HdmiContentType | ||
| 122 | enum class HdmiContentType : u32 { | ||
| 123 | None, | ||
| 124 | Graphics, | ||
| 125 | Cinema, | ||
| 126 | Photo, | ||
| 127 | Game, | ||
| 128 | }; | ||
| 129 | |||
| 130 | enum class KeyboardLayout : u32 { | ||
| 131 | Japanese = 0, | ||
| 132 | EnglishUs = 1, | ||
| 133 | EnglishUsInternational = 2, | ||
| 134 | EnglishUk = 3, | ||
| 135 | French = 4, | ||
| 136 | FrenchCa = 5, | ||
| 137 | Spanish = 6, | ||
| 138 | SpanishLatin = 7, | ||
| 139 | German = 8, | ||
| 140 | Italian = 9, | ||
| 141 | Portuguese = 10, | ||
| 142 | Russian = 11, | ||
| 143 | Korean = 12, | ||
| 144 | ChineseSimplified = 13, | ||
| 145 | ChineseTraditional = 14, | ||
| 146 | }; | ||
| 147 | |||
| 148 | /// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. | ||
| 149 | enum class LanguageCode : u64 { | ||
| 150 | JA = 0x000000000000616A, | ||
| 151 | EN_US = 0x00000053552D6E65, | ||
| 152 | FR = 0x0000000000007266, | ||
| 153 | DE = 0x0000000000006564, | ||
| 154 | IT = 0x0000000000007469, | ||
| 155 | ES = 0x0000000000007365, | ||
| 156 | ZH_CN = 0x0000004E432D687A, | ||
| 157 | KO = 0x0000000000006F6B, | ||
| 158 | NL = 0x0000000000006C6E, | ||
| 159 | PT = 0x0000000000007470, | ||
| 160 | RU = 0x0000000000007572, | ||
| 161 | ZH_TW = 0x00000057542D687A, | ||
| 162 | EN_GB = 0x00000042472D6E65, | ||
| 163 | FR_CA = 0x00000041432D7266, | ||
| 164 | ES_419 = 0x00003931342D7365, | ||
| 165 | ZH_HANS = 0x00736E61482D687A, | ||
| 166 | ZH_HANT = 0x00746E61482D687A, | ||
| 167 | PT_BR = 0x00000052422D7470, | ||
| 168 | }; | ||
| 169 | |||
| 170 | /// This is nn::settings::system::NotificationVolume | ||
| 171 | enum class NotificationVolume : u32 { | ||
| 172 | Mute, | ||
| 173 | Low, | ||
| 174 | High, | ||
| 175 | }; | ||
| 176 | |||
| 177 | /// This is nn::settings::system::PrimaryAlbumStorage | ||
| 178 | enum class PrimaryAlbumStorage : u32 { | ||
| 179 | Nand, | ||
| 180 | SdCard, | ||
| 181 | }; | ||
| 182 | |||
| 183 | /// Indicates the current console is a retail or kiosk unit | ||
| 184 | enum class QuestFlag : u8 { | ||
| 185 | Retail = 0, | ||
| 186 | Kiosk = 1, | ||
| 187 | }; | ||
| 188 | |||
| 189 | /// This is nn::settings::system::RgbRange | ||
| 190 | enum class RgbRange : u32 { | ||
| 191 | Auto, | ||
| 192 | Full, | ||
| 193 | Limited, | ||
| 194 | }; | ||
| 195 | |||
| 196 | /// This is nn::settings::system::RegionCode | ||
| 197 | enum class SystemRegionCode : u32 { | ||
| 198 | Japan, | ||
| 199 | Usa, | ||
| 200 | Europe, | ||
| 201 | Australia, | ||
| 202 | HongKongTaiwanKorea, | ||
| 203 | China, | ||
| 204 | }; | ||
| 205 | |||
| 206 | /// This is nn::settings::system::TouchScreenMode | ||
| 207 | enum class TouchScreenMode : u32 { | ||
| 208 | Stylus, | ||
| 209 | Standard, | ||
| 210 | }; | ||
| 211 | |||
| 212 | /// This is nn::settings::system::TvResolution | ||
| 213 | enum class TvResolution : u32 { | ||
| 214 | Auto, | ||
| 215 | Resolution1080p, | ||
| 216 | Resolution720p, | ||
| 217 | Resolution480p, | ||
| 218 | }; | ||
| 219 | |||
| 220 | constexpr std::array<LanguageCode, 18> available_language_codes = {{ | ||
| 221 | LanguageCode::JA, | ||
| 222 | LanguageCode::EN_US, | ||
| 223 | LanguageCode::FR, | ||
| 224 | LanguageCode::DE, | ||
| 225 | LanguageCode::IT, | ||
| 226 | LanguageCode::ES, | ||
| 227 | LanguageCode::ZH_CN, | ||
| 228 | LanguageCode::KO, | ||
| 229 | LanguageCode::NL, | ||
| 230 | LanguageCode::PT, | ||
| 231 | LanguageCode::RU, | ||
| 232 | LanguageCode::ZH_TW, | ||
| 233 | LanguageCode::EN_GB, | ||
| 234 | LanguageCode::FR_CA, | ||
| 235 | LanguageCode::ES_419, | ||
| 236 | LanguageCode::ZH_HANS, | ||
| 237 | LanguageCode::ZH_HANT, | ||
| 238 | LanguageCode::PT_BR, | ||
| 239 | }}; | ||
| 240 | |||
| 241 | static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{ | ||
| 242 | {LanguageCode::JA, KeyboardLayout::Japanese}, | ||
| 243 | {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, | ||
| 244 | {LanguageCode::FR, KeyboardLayout::French}, | ||
| 245 | {LanguageCode::DE, KeyboardLayout::German}, | ||
| 246 | {LanguageCode::IT, KeyboardLayout::Italian}, | ||
| 247 | {LanguageCode::ES, KeyboardLayout::Spanish}, | ||
| 248 | {LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified}, | ||
| 249 | {LanguageCode::KO, KeyboardLayout::Korean}, | ||
| 250 | {LanguageCode::NL, KeyboardLayout::EnglishUsInternational}, | ||
| 251 | {LanguageCode::PT, KeyboardLayout::Portuguese}, | ||
| 252 | {LanguageCode::RU, KeyboardLayout::Russian}, | ||
| 253 | {LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional}, | ||
| 254 | {LanguageCode::EN_GB, KeyboardLayout::EnglishUk}, | ||
| 255 | {LanguageCode::FR_CA, KeyboardLayout::FrenchCa}, | ||
| 256 | {LanguageCode::ES_419, KeyboardLayout::SpanishLatin}, | ||
| 257 | {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, | ||
| 258 | {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, | ||
| 259 | {LanguageCode::PT_BR, KeyboardLayout::Portuguese}, | ||
| 260 | }}; | ||
| 261 | |||
| 262 | /// This is nn::settings::system::AccountNotificationFlag | ||
| 263 | struct AccountNotificationFlag { | ||
| 264 | union { | ||
| 265 | u32 raw{}; | ||
| 266 | |||
| 267 | BitField<0, 1, u32> FriendOnlineFlag; | ||
| 268 | BitField<1, 1, u32> FriendRequestFlag; | ||
| 269 | BitField<8, 1, u32> CoralInvitationFlag; | ||
| 270 | }; | ||
| 271 | }; | ||
| 272 | static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size"); | ||
| 273 | |||
| 274 | /// This is nn::settings::system::AccountSettings | ||
| 275 | struct AccountSettings { | ||
| 276 | u32 flags; | ||
| 277 | }; | ||
| 278 | static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size"); | ||
| 279 | |||
| 280 | /// This is nn::settings::system::DataDeletionFlag | ||
| 281 | struct DataDeletionFlag { | ||
| 282 | union { | ||
| 283 | u32 raw{}; | ||
| 284 | |||
| 285 | BitField<0, 1, u32> AutomaticDeletionFlag; | ||
| 286 | }; | ||
| 287 | }; | ||
| 288 | static_assert(sizeof(DataDeletionFlag) == 4, "DataDeletionFlag is an invalid size"); | ||
| 289 | |||
| 290 | /// This is nn::settings::system::InitialLaunchFlag | ||
| 291 | struct InitialLaunchFlag { | ||
| 292 | union { | ||
| 293 | u32 raw{}; | ||
| 294 | |||
| 295 | BitField<0, 1, u32> InitialLaunchCompletionFlag; | ||
| 296 | BitField<8, 1, u32> InitialLaunchUserAdditionFlag; | ||
| 297 | BitField<16, 1, u32> InitialLaunchTimestampFlag; | ||
| 298 | }; | ||
| 299 | }; | ||
| 300 | static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size"); | ||
| 301 | |||
| 302 | /// This is nn::settings::system::SleepFlag | ||
| 303 | struct SleepFlag { | ||
| 304 | union { | ||
| 305 | u32 raw{}; | ||
| 306 | |||
| 307 | BitField<0, 1, u32> SleepsWhilePlayingMedia; | ||
| 308 | BitField<1, 1, u32> WakesAtPowerStateChange; | ||
| 309 | }; | ||
| 310 | }; | ||
| 311 | static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size"); | ||
| 312 | |||
| 313 | /// This is nn::settings::system::NotificationFlag | ||
| 314 | struct NotificationFlag { | ||
| 315 | union { | ||
| 316 | u32 raw{}; | ||
| 317 | |||
| 318 | BitField<0, 1, u32> RingtoneFlag; | ||
| 319 | BitField<1, 1, u32> DownloadCompletionFlag; | ||
| 320 | BitField<8, 1, u32> EnablesNews; | ||
| 321 | BitField<9, 1, u32> IncomingLampFlag; | ||
| 322 | }; | ||
| 323 | }; | ||
| 324 | static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size"); | ||
| 325 | |||
| 326 | /// This is nn::settings::system::TvFlag | ||
| 327 | struct TvFlag { | ||
| 328 | union { | ||
| 329 | u32 raw{}; | ||
| 330 | |||
| 331 | BitField<0, 1, u32> Allows4k; | ||
| 332 | BitField<1, 1, u32> Allows3d; | ||
| 333 | BitField<2, 1, u32> AllowsCec; | ||
| 334 | BitField<3, 1, u32> PreventsScreenBurnIn; | ||
| 335 | }; | ||
| 336 | }; | ||
| 337 | static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size"); | ||
| 338 | |||
| 339 | /// This is nn::settings::system::UserSelectorFlag | ||
| 340 | struct UserSelectorFlag { | ||
| 341 | union { | ||
| 342 | u32 raw{}; | ||
| 343 | |||
| 344 | BitField<0, 1, u32> SkipIfSingleUser; | ||
| 345 | BitField<31, 1, u32> Unknown; | ||
| 346 | }; | ||
| 347 | }; | ||
| 348 | static_assert(sizeof(UserSelectorFlag) == 4, "UserSelectorFlag is an invalid size"); | ||
| 349 | |||
| 350 | /// This is nn::settings::system::AccountNotificationSettings | ||
| 351 | struct AccountNotificationSettings { | ||
| 352 | Common::UUID uid; | ||
| 353 | AccountNotificationFlag flags; | ||
| 354 | FriendPresenceOverlayPermission friend_presence_permission; | ||
| 355 | FriendPresenceOverlayPermission friend_invitation_permission; | ||
| 356 | INSERT_PADDING_BYTES(0x2); | ||
| 357 | }; | ||
| 358 | static_assert(sizeof(AccountNotificationSettings) == 0x18, | ||
| 359 | "AccountNotificationSettings is an invalid size"); | ||
| 360 | |||
| 361 | /// This is nn::settings::system::EulaVersion | ||
| 362 | struct EulaVersion { | ||
| 363 | u32 version; | ||
| 364 | SystemRegionCode region_code; | ||
| 365 | EulaVersionClockType clock_type; | ||
| 366 | INSERT_PADDING_BYTES(0x4); | ||
| 367 | s64 posix_time; | ||
| 368 | Time::Clock::SteadyClockTimePoint timestamp; | ||
| 369 | }; | ||
| 370 | static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); | ||
| 371 | |||
| 372 | struct FirmwareVersionFormat { | ||
| 373 | u8 major; | ||
| 374 | u8 minor; | ||
| 375 | u8 micro; | ||
| 376 | INSERT_PADDING_BYTES(1); | ||
| 377 | u8 revision_major; | ||
| 378 | u8 revision_minor; | ||
| 379 | INSERT_PADDING_BYTES(2); | ||
| 380 | std::array<char, 0x20> platform; | ||
| 381 | std::array<u8, 0x40> version_hash; | ||
| 382 | std::array<char, 0x18> display_version; | ||
| 383 | std::array<char, 0x80> display_title; | ||
| 384 | }; | ||
| 385 | static_assert(sizeof(FirmwareVersionFormat) == 0x100, "FirmwareVersionFormat is an invalid size"); | ||
| 386 | |||
| 387 | /// This is nn::settings::system::HomeMenuScheme | ||
| 388 | struct HomeMenuScheme { | ||
| 389 | u32 main; | ||
| 390 | u32 back; | ||
| 391 | u32 sub; | ||
| 392 | u32 bezel; | ||
| 393 | u32 extra; | ||
| 394 | }; | ||
| 395 | static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size"); | ||
| 396 | |||
| 397 | /// This is nn::settings::system::InitialLaunchSettings | ||
| 398 | struct InitialLaunchSettings { | ||
| 399 | InitialLaunchFlag flags; | ||
| 400 | INSERT_PADDING_BYTES(0x4); | ||
| 401 | Service::Time::Clock::SteadyClockTimePoint timestamp; | ||
| 402 | }; | ||
| 403 | static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); | ||
| 404 | |||
| 405 | #pragma pack(push, 4) | ||
| 406 | struct InitialLaunchSettingsPacked { | ||
| 407 | InitialLaunchFlag flags; | ||
| 408 | Service::Time::Clock::SteadyClockTimePoint timestamp; | ||
| 409 | }; | ||
| 410 | #pragma pack(pop) | ||
| 411 | static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, | ||
| 412 | "InitialLaunchSettingsPacked is incorrect size"); | ||
| 413 | |||
| 414 | /// This is nn::settings::system::NotificationTime | ||
| 415 | struct NotificationTime { | ||
| 416 | u32 hour; | ||
| 417 | u32 minute; | ||
| 418 | }; | ||
| 419 | static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size"); | ||
| 420 | |||
| 421 | /// This is nn::settings::system::NotificationSettings | ||
| 422 | struct NotificationSettings { | ||
| 423 | NotificationFlag flags; | ||
| 424 | NotificationVolume volume; | ||
| 425 | NotificationTime start_time; | ||
| 426 | NotificationTime stop_time; | ||
| 427 | }; | ||
| 428 | static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size"); | ||
| 429 | |||
| 430 | /// This is nn::settings::system::SleepSettings | ||
| 431 | struct SleepSettings { | ||
| 432 | SleepFlag flags; | ||
| 433 | HandheldSleepPlan handheld_sleep_plan; | ||
| 434 | ConsoleSleepPlan console_sleep_plan; | ||
| 435 | }; | ||
| 436 | static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size"); | ||
| 437 | |||
| 438 | /// This is nn::settings::system::TvSettings | ||
| 439 | struct TvSettings { | ||
| 440 | TvFlag flags; | ||
| 441 | TvResolution tv_resolution; | ||
| 442 | HdmiContentType hdmi_content_type; | ||
| 443 | RgbRange rgb_range; | ||
| 444 | CmuMode cmu_mode; | ||
| 445 | u32 tv_underscan; | ||
| 446 | f32 tv_gama; | ||
| 447 | f32 contrast_ratio; | ||
| 448 | }; | ||
| 449 | static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); | ||
| 450 | |||
| 451 | } // namespace Service::Set | ||
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp index af9348522..87242ae68 100644 --- a/src/core/hle/service/set/system_settings_server.cpp +++ b/src/core/hle/service/set/system_settings_server.cpp | |||
| @@ -97,8 +97,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_) | |||
| 97 | {3, &ISystemSettingsServer::GetFirmwareVersion, "GetFirmwareVersion"}, | 97 | {3, &ISystemSettingsServer::GetFirmwareVersion, "GetFirmwareVersion"}, |
| 98 | {4, &ISystemSettingsServer::GetFirmwareVersion2, "GetFirmwareVersion2"}, | 98 | {4, &ISystemSettingsServer::GetFirmwareVersion2, "GetFirmwareVersion2"}, |
| 99 | {5, nullptr, "GetFirmwareVersionDigest"}, | 99 | {5, nullptr, "GetFirmwareVersionDigest"}, |
| 100 | {7, nullptr, "GetLockScreenFlag"}, | 100 | {7, &ISystemSettingsServer::GetLockScreenFlag, "GetLockScreenFlag"}, |
| 101 | {8, nullptr, "SetLockScreenFlag"}, | 101 | {8, &ISystemSettingsServer::SetLockScreenFlag, "SetLockScreenFlag"}, |
| 102 | {9, nullptr, "GetBacklightSettings"}, | 102 | {9, nullptr, "GetBacklightSettings"}, |
| 103 | {10, nullptr, "SetBacklightSettings"}, | 103 | {10, nullptr, "SetBacklightSettings"}, |
| 104 | {11, nullptr, "SetBluetoothDevicesSettings"}, | 104 | {11, nullptr, "SetBluetoothDevicesSettings"}, |
| @@ -157,12 +157,12 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_) | |||
| 157 | {66, nullptr, "SetUsb30EnableFlag"}, | 157 | {66, nullptr, "SetUsb30EnableFlag"}, |
| 158 | {67, nullptr, "GetBatteryLot"}, | 158 | {67, nullptr, "GetBatteryLot"}, |
| 159 | {68, nullptr, "GetSerialNumber"}, | 159 | {68, nullptr, "GetSerialNumber"}, |
| 160 | {69, nullptr, "GetNfcEnableFlag"}, | 160 | {69, &ISystemSettingsServer::GetNfcEnableFlag, "GetNfcEnableFlag"}, |
| 161 | {70, nullptr, "SetNfcEnableFlag"}, | 161 | {70, &ISystemSettingsServer::SetNfcEnableFlag, "SetNfcEnableFlag"}, |
| 162 | {71, &ISystemSettingsServer::GetSleepSettings, "GetSleepSettings"}, | 162 | {71, &ISystemSettingsServer::GetSleepSettings, "GetSleepSettings"}, |
| 163 | {72, &ISystemSettingsServer::SetSleepSettings, "SetSleepSettings"}, | 163 | {72, &ISystemSettingsServer::SetSleepSettings, "SetSleepSettings"}, |
| 164 | {73, nullptr, "GetWirelessLanEnableFlag"}, | 164 | {73, &ISystemSettingsServer::GetWirelessLanEnableFlag, "GetWirelessLanEnableFlag"}, |
| 165 | {74, nullptr, "SetWirelessLanEnableFlag"}, | 165 | {74, &ISystemSettingsServer::SetWirelessLanEnableFlag, "SetWirelessLanEnableFlag"}, |
| 166 | {75, &ISystemSettingsServer::GetInitialLaunchSettings, "GetInitialLaunchSettings"}, | 166 | {75, &ISystemSettingsServer::GetInitialLaunchSettings, "GetInitialLaunchSettings"}, |
| 167 | {76, &ISystemSettingsServer::SetInitialLaunchSettings, "SetInitialLaunchSettings"}, | 167 | {76, &ISystemSettingsServer::SetInitialLaunchSettings, "SetInitialLaunchSettings"}, |
| 168 | {77, &ISystemSettingsServer::GetDeviceNickName, "GetDeviceNickName"}, | 168 | {77, &ISystemSettingsServer::GetDeviceNickName, "GetDeviceNickName"}, |
| @@ -176,8 +176,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_) | |||
| 176 | {85, nullptr, "SetPtmBatteryLot"}, | 176 | {85, nullptr, "SetPtmBatteryLot"}, |
| 177 | {86, nullptr, "GetPtmFuelGaugeParameter"}, | 177 | {86, nullptr, "GetPtmFuelGaugeParameter"}, |
| 178 | {87, nullptr, "SetPtmFuelGaugeParameter"}, | 178 | {87, nullptr, "SetPtmFuelGaugeParameter"}, |
| 179 | {88, nullptr, "GetBluetoothEnableFlag"}, | 179 | {88, &ISystemSettingsServer::GetBluetoothEnableFlag, "GetBluetoothEnableFlag"}, |
| 180 | {89, nullptr, "SetBluetoothEnableFlag"}, | 180 | {89, &ISystemSettingsServer::SetBluetoothEnableFlag, "SetBluetoothEnableFlag"}, |
| 181 | {90, &ISystemSettingsServer::GetMiiAuthorId, "GetMiiAuthorId"}, | 181 | {90, &ISystemSettingsServer::GetMiiAuthorId, "GetMiiAuthorId"}, |
| 182 | {91, nullptr, "SetShutdownRtcValue"}, | 182 | {91, nullptr, "SetShutdownRtcValue"}, |
| 183 | {92, nullptr, "GetShutdownRtcValue"}, | 183 | {92, nullptr, "GetShutdownRtcValue"}, |
| @@ -510,6 +510,25 @@ void ISystemSettingsServer::SetUserSystemClockContext(HLERequestContext& ctx) { | |||
| 510 | rb.Push(res); | 510 | rb.Push(res); |
| 511 | } | 511 | } |
| 512 | 512 | ||
| 513 | void ISystemSettingsServer::GetLockScreenFlag(HLERequestContext& ctx) { | ||
| 514 | LOG_INFO(Service_SET, "called, lock_screen_flag={}", m_system_settings.lock_screen_flag); | ||
| 515 | |||
| 516 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 517 | rb.Push(ResultSuccess); | ||
| 518 | rb.Push(m_system_settings.lock_screen_flag); | ||
| 519 | } | ||
| 520 | |||
| 521 | void ISystemSettingsServer::SetLockScreenFlag(HLERequestContext& ctx) { | ||
| 522 | IPC::RequestParser rp{ctx}; | ||
| 523 | m_system_settings.lock_screen_flag = rp.Pop<bool>(); | ||
| 524 | SetSaveNeeded(); | ||
| 525 | |||
| 526 | LOG_INFO(Service_SET, "called, lock_screen_flag={}", m_system_settings.lock_screen_flag); | ||
| 527 | |||
| 528 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 529 | rb.Push(ResultSuccess); | ||
| 530 | } | ||
| 531 | |||
| 513 | void ISystemSettingsServer::GetAccountSettings(HLERequestContext& ctx) { | 532 | void ISystemSettingsServer::GetAccountSettings(HLERequestContext& ctx) { |
| 514 | LOG_INFO(Service_SET, "called"); | 533 | LOG_INFO(Service_SET, "called"); |
| 515 | 534 | ||
| @@ -531,7 +550,7 @@ void ISystemSettingsServer::SetAccountSettings(HLERequestContext& ctx) { | |||
| 531 | } | 550 | } |
| 532 | 551 | ||
| 533 | void ISystemSettingsServer::GetEulaVersions(HLERequestContext& ctx) { | 552 | void ISystemSettingsServer::GetEulaVersions(HLERequestContext& ctx) { |
| 534 | LOG_INFO(Service_SET, "called"); | 553 | LOG_INFO(Service_SET, "called, elements={}", m_system_settings.eula_version_count); |
| 535 | 554 | ||
| 536 | ctx.WriteBuffer(m_system_settings.eula_versions); | 555 | ctx.WriteBuffer(m_system_settings.eula_versions); |
| 537 | 556 | ||
| @@ -557,7 +576,7 @@ void ISystemSettingsServer::SetEulaVersions(HLERequestContext& ctx) { | |||
| 557 | } | 576 | } |
| 558 | 577 | ||
| 559 | void ISystemSettingsServer::GetColorSetId(HLERequestContext& ctx) { | 578 | void ISystemSettingsServer::GetColorSetId(HLERequestContext& ctx) { |
| 560 | LOG_DEBUG(Service_SET, "called"); | 579 | LOG_DEBUG(Service_SET, "called, color_set=", m_system_settings.color_set_id); |
| 561 | 580 | ||
| 562 | IPC::ResponseBuilder rb{ctx, 3}; | 581 | IPC::ResponseBuilder rb{ctx, 3}; |
| 563 | rb.Push(ResultSuccess); | 582 | rb.Push(ResultSuccess); |
| @@ -576,7 +595,13 @@ void ISystemSettingsServer::SetColorSetId(HLERequestContext& ctx) { | |||
| 576 | } | 595 | } |
| 577 | 596 | ||
| 578 | void ISystemSettingsServer::GetNotificationSettings(HLERequestContext& ctx) { | 597 | void ISystemSettingsServer::GetNotificationSettings(HLERequestContext& ctx) { |
| 579 | LOG_INFO(Service_SET, "called"); | 598 | LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}", |
| 599 | m_system_settings.notification_settings.flags.raw, | ||
| 600 | m_system_settings.notification_settings.volume, | ||
| 601 | m_system_settings.notification_settings.start_time.hour, | ||
| 602 | m_system_settings.notification_settings.start_time.minute, | ||
| 603 | m_system_settings.notification_settings.stop_time.hour, | ||
| 604 | m_system_settings.notification_settings.stop_time.minute); | ||
| 580 | 605 | ||
| 581 | IPC::ResponseBuilder rb{ctx, 8}; | 606 | IPC::ResponseBuilder rb{ctx, 8}; |
| 582 | rb.Push(ResultSuccess); | 607 | rb.Push(ResultSuccess); |
| @@ -601,7 +626,8 @@ void ISystemSettingsServer::SetNotificationSettings(HLERequestContext& ctx) { | |||
| 601 | } | 626 | } |
| 602 | 627 | ||
| 603 | void ISystemSettingsServer::GetAccountNotificationSettings(HLERequestContext& ctx) { | 628 | void ISystemSettingsServer::GetAccountNotificationSettings(HLERequestContext& ctx) { |
| 604 | LOG_INFO(Service_SET, "called"); | 629 | LOG_INFO(Service_SET, "called, elements={}", |
| 630 | m_system_settings.account_notification_settings_count); | ||
| 605 | 631 | ||
| 606 | ctx.WriteBuffer(m_system_settings.account_notification_settings); | 632 | ctx.WriteBuffer(m_system_settings.account_notification_settings); |
| 607 | 633 | ||
| @@ -645,6 +671,7 @@ using Settings = | |||
| 645 | static Settings GetSettings() { | 671 | static Settings GetSettings() { |
| 646 | Settings ret; | 672 | Settings ret; |
| 647 | 673 | ||
| 674 | // AM | ||
| 648 | ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0}); | 675 | ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0}); |
| 649 | ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000}); | 676 | ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000}); |
| 650 | 677 | ||
| @@ -656,6 +683,24 @@ static Settings GetSettings() { | |||
| 656 | ret["time"]["standard_steady_clock_test_offset_minutes"] = ToBytes(s32{0}); | 683 | ret["time"]["standard_steady_clock_test_offset_minutes"] = ToBytes(s32{0}); |
| 657 | ret["time"]["standard_user_clock_initial_year"] = ToBytes(s32{2023}); | 684 | ret["time"]["standard_user_clock_initial_year"] = ToBytes(s32{2023}); |
| 658 | 685 | ||
| 686 | // HID | ||
| 687 | ret["hid_debug"]["enables_debugpad"] = ToBytes(bool{true}); | ||
| 688 | ret["hid_debug"]["manages_devices"] = ToBytes(bool{true}); | ||
| 689 | ret["hid_debug"]["manages_touch_ic_i2c"] = ToBytes(bool{true}); | ||
| 690 | ret["hid_debug"]["emulate_future_device"] = ToBytes(bool{false}); | ||
| 691 | ret["hid_debug"]["emulate_mcu_hardware_error"] = ToBytes(bool{false}); | ||
| 692 | ret["hid_debug"]["enables_rail"] = ToBytes(bool{true}); | ||
| 693 | ret["hid_debug"]["emulate_firmware_update_failure"] = ToBytes(bool{false}); | ||
| 694 | ret["hid_debug"]["failure_firmware_update"] = ToBytes(s32{0}); | ||
| 695 | ret["hid_debug"]["ble_disabled"] = ToBytes(bool{false}); | ||
| 696 | ret["hid_debug"]["dscale_disabled"] = ToBytes(bool{false}); | ||
| 697 | ret["hid_debug"]["force_handheld"] = ToBytes(bool{true}); | ||
| 698 | ret["hid_debug"]["disabled_features_per_id"] = std::vector<u8>(0xa8); | ||
| 699 | ret["hid_debug"]["touch_firmware_auto_update_disabled"] = ToBytes(bool{false}); | ||
| 700 | |||
| 701 | // Settings | ||
| 702 | ret["settings_debug"]["is_debug_mode_enabled"] = ToBytes(bool{false}); | ||
| 703 | |||
| 659 | return ret; | 704 | return ret; |
| 660 | } | 705 | } |
| 661 | 706 | ||
| @@ -708,7 +753,15 @@ void ISystemSettingsServer::GetSettingsItemValue(HLERequestContext& ctx) { | |||
| 708 | } | 753 | } |
| 709 | 754 | ||
| 710 | void ISystemSettingsServer::GetTvSettings(HLERequestContext& ctx) { | 755 | void ISystemSettingsServer::GetTvSettings(HLERequestContext& ctx) { |
| 711 | LOG_INFO(Service_SET, "called"); | 756 | LOG_INFO(Service_SET, |
| 757 | "called, flags={}, cmu_mode={}, contrast_ratio={}, hdmi_content_type={}, " | ||
| 758 | "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", | ||
| 759 | m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, | ||
| 760 | m_system_settings.tv_settings.contrast_ratio, | ||
| 761 | m_system_settings.tv_settings.hdmi_content_type, | ||
| 762 | m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, | ||
| 763 | m_system_settings.tv_settings.tv_resolution, | ||
| 764 | m_system_settings.tv_settings.tv_underscan); | ||
| 712 | 765 | ||
| 713 | IPC::ResponseBuilder rb{ctx, 10}; | 766 | IPC::ResponseBuilder rb{ctx, 10}; |
| 714 | rb.Push(ResultSuccess); | 767 | rb.Push(ResultSuccess); |
| @@ -735,23 +788,26 @@ void ISystemSettingsServer::SetTvSettings(HLERequestContext& ctx) { | |||
| 735 | } | 788 | } |
| 736 | 789 | ||
| 737 | void ISystemSettingsServer::GetDebugModeFlag(HLERequestContext& ctx) { | 790 | void ISystemSettingsServer::GetDebugModeFlag(HLERequestContext& ctx) { |
| 738 | LOG_DEBUG(Service_SET, "called"); | 791 | bool is_debug_mode_enabled = false; |
| 792 | GetSettingsItemValue<bool>(is_debug_mode_enabled, "settings_debug", "is_debug_mode_enabled"); | ||
| 793 | |||
| 794 | LOG_DEBUG(Service_SET, "called, is_debug_mode_enabled={}", is_debug_mode_enabled); | ||
| 739 | 795 | ||
| 740 | IPC::ResponseBuilder rb{ctx, 3}; | 796 | IPC::ResponseBuilder rb{ctx, 3}; |
| 741 | rb.Push(ResultSuccess); | 797 | rb.Push(ResultSuccess); |
| 742 | rb.Push<u32>(0); | 798 | rb.Push(is_debug_mode_enabled); |
| 743 | } | 799 | } |
| 744 | 800 | ||
| 745 | void ISystemSettingsServer::GetQuestFlag(HLERequestContext& ctx) { | 801 | void ISystemSettingsServer::GetQuestFlag(HLERequestContext& ctx) { |
| 746 | LOG_WARNING(Service_SET, "(STUBBED) called"); | 802 | LOG_INFO(Service_SET, "called, quest_flag={}", m_system_settings.quest_flag); |
| 747 | 803 | ||
| 748 | IPC::ResponseBuilder rb{ctx, 3}; | 804 | IPC::ResponseBuilder rb{ctx, 3}; |
| 749 | rb.Push(ResultSuccess); | 805 | rb.Push(ResultSuccess); |
| 750 | rb.PushEnum(QuestFlag::Retail); | 806 | rb.PushEnum(m_system_settings.quest_flag); |
| 751 | } | 807 | } |
| 752 | 808 | ||
| 753 | void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) { | 809 | void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) { |
| 754 | LOG_WARNING(Service_SET, "called"); | 810 | LOG_INFO(Service_SET, "called"); |
| 755 | 811 | ||
| 756 | Service::Time::TimeZone::LocationName name{}; | 812 | Service::Time::TimeZone::LocationName name{}; |
| 757 | auto res = GetDeviceTimeZoneLocationName(name); | 813 | auto res = GetDeviceTimeZoneLocationName(name); |
| @@ -762,7 +818,7 @@ void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx | |||
| 762 | } | 818 | } |
| 763 | 819 | ||
| 764 | void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) { | 820 | void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) { |
| 765 | LOG_WARNING(Service_SET, "called"); | 821 | LOG_INFO(Service_SET, "called"); |
| 766 | 822 | ||
| 767 | IPC::RequestParser rp{ctx}; | 823 | IPC::RequestParser rp{ctx}; |
| 768 | auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()}; | 824 | auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()}; |
| @@ -775,7 +831,7 @@ void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx | |||
| 775 | 831 | ||
| 776 | void ISystemSettingsServer::SetRegionCode(HLERequestContext& ctx) { | 832 | void ISystemSettingsServer::SetRegionCode(HLERequestContext& ctx) { |
| 777 | IPC::RequestParser rp{ctx}; | 833 | IPC::RequestParser rp{ctx}; |
| 778 | m_system_settings.region_code = rp.PopEnum<RegionCode>(); | 834 | m_system_settings.region_code = rp.PopEnum<SystemRegionCode>(); |
| 779 | SetSaveNeeded(); | 835 | SetSaveNeeded(); |
| 780 | 836 | ||
| 781 | LOG_INFO(Service_SET, "called, region_code={}", m_system_settings.region_code); | 837 | LOG_INFO(Service_SET, "called, region_code={}", m_system_settings.region_code); |
| @@ -832,15 +888,38 @@ void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionEnabled(HLERequ | |||
| 832 | } | 888 | } |
| 833 | 889 | ||
| 834 | void ISystemSettingsServer::GetPrimaryAlbumStorage(HLERequestContext& ctx) { | 890 | void ISystemSettingsServer::GetPrimaryAlbumStorage(HLERequestContext& ctx) { |
| 835 | LOG_WARNING(Service_SET, "(STUBBED) called"); | 891 | LOG_INFO(Service_SET, "called, primary_album_storage={}", |
| 892 | m_system_settings.primary_album_storage); | ||
| 893 | |||
| 894 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 895 | rb.Push(ResultSuccess); | ||
| 896 | rb.PushEnum(m_system_settings.primary_album_storage); | ||
| 897 | } | ||
| 898 | |||
| 899 | void ISystemSettingsServer::GetNfcEnableFlag(HLERequestContext& ctx) { | ||
| 900 | LOG_INFO(Service_SET, "called, nfc_enable_flag={}", m_system_settings.nfc_enable_flag); | ||
| 836 | 901 | ||
| 837 | IPC::ResponseBuilder rb{ctx, 3}; | 902 | IPC::ResponseBuilder rb{ctx, 3}; |
| 838 | rb.Push(ResultSuccess); | 903 | rb.Push(ResultSuccess); |
| 839 | rb.PushEnum(PrimaryAlbumStorage::SdCard); | 904 | rb.Push<u8>(m_system_settings.nfc_enable_flag); |
| 905 | } | ||
| 906 | |||
| 907 | void ISystemSettingsServer::SetNfcEnableFlag(HLERequestContext& ctx) { | ||
| 908 | IPC::RequestParser rp{ctx}; | ||
| 909 | m_system_settings.nfc_enable_flag = rp.Pop<bool>(); | ||
| 910 | SetSaveNeeded(); | ||
| 911 | |||
| 912 | LOG_INFO(Service_SET, "called, nfc_enable_flag={}", m_system_settings.nfc_enable_flag); | ||
| 913 | |||
| 914 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 915 | rb.Push(ResultSuccess); | ||
| 840 | } | 916 | } |
| 841 | 917 | ||
| 842 | void ISystemSettingsServer::GetSleepSettings(HLERequestContext& ctx) { | 918 | void ISystemSettingsServer::GetSleepSettings(HLERequestContext& ctx) { |
| 843 | LOG_INFO(Service_SET, "called"); | 919 | LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}", |
| 920 | m_system_settings.sleep_settings.flags.raw, | ||
| 921 | m_system_settings.sleep_settings.handheld_sleep_plan, | ||
| 922 | m_system_settings.sleep_settings.console_sleep_plan); | ||
| 844 | 923 | ||
| 845 | IPC::ResponseBuilder rb{ctx, 5}; | 924 | IPC::ResponseBuilder rb{ctx, 5}; |
| 846 | rb.Push(ResultSuccess); | 925 | rb.Push(ResultSuccess); |
| @@ -861,8 +940,32 @@ void ISystemSettingsServer::SetSleepSettings(HLERequestContext& ctx) { | |||
| 861 | rb.Push(ResultSuccess); | 940 | rb.Push(ResultSuccess); |
| 862 | } | 941 | } |
| 863 | 942 | ||
| 943 | void ISystemSettingsServer::GetWirelessLanEnableFlag(HLERequestContext& ctx) { | ||
| 944 | LOG_INFO(Service_SET, "called, wireless_lan_enable_flag={}", | ||
| 945 | m_system_settings.wireless_lan_enable_flag); | ||
| 946 | |||
| 947 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 948 | rb.Push(ResultSuccess); | ||
| 949 | rb.Push(m_system_settings.wireless_lan_enable_flag); | ||
| 950 | } | ||
| 951 | |||
| 952 | void ISystemSettingsServer::SetWirelessLanEnableFlag(HLERequestContext& ctx) { | ||
| 953 | IPC::RequestParser rp{ctx}; | ||
| 954 | m_system_settings.wireless_lan_enable_flag = rp.Pop<bool>(); | ||
| 955 | SetSaveNeeded(); | ||
| 956 | |||
| 957 | LOG_INFO(Service_SET, "called, wireless_lan_enable_flag={}", | ||
| 958 | m_system_settings.wireless_lan_enable_flag); | ||
| 959 | |||
| 960 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 961 | rb.Push(ResultSuccess); | ||
| 962 | } | ||
| 963 | |||
| 864 | void ISystemSettingsServer::GetInitialLaunchSettings(HLERequestContext& ctx) { | 964 | void ISystemSettingsServer::GetInitialLaunchSettings(HLERequestContext& ctx) { |
| 865 | LOG_INFO(Service_SET, "called"); | 965 | LOG_INFO(Service_SET, "called, flags={}, timestamp={}", |
| 966 | m_system_settings.initial_launch_settings_packed.flags.raw, | ||
| 967 | m_system_settings.initial_launch_settings_packed.timestamp.time_point); | ||
| 968 | |||
| 866 | IPC::ResponseBuilder rb{ctx, 10}; | 969 | IPC::ResponseBuilder rb{ctx, 10}; |
| 867 | rb.Push(ResultSuccess); | 970 | rb.Push(ResultSuccess); |
| 868 | rb.PushRaw(m_system_settings.initial_launch_settings_packed); | 971 | rb.PushRaw(m_system_settings.initial_launch_settings_packed); |
| @@ -913,35 +1016,51 @@ void ISystemSettingsServer::GetProductModel(HLERequestContext& ctx) { | |||
| 913 | rb.Push(product_model); | 1016 | rb.Push(product_model); |
| 914 | } | 1017 | } |
| 915 | 1018 | ||
| 916 | void ISystemSettingsServer::GetMiiAuthorId(HLERequestContext& ctx) { | 1019 | void ISystemSettingsServer::GetBluetoothEnableFlag(HLERequestContext& ctx) { |
| 917 | const auto author_id = Common::UUID::MakeDefault(); | 1020 | LOG_INFO(Service_SET, "called, bluetooth_enable_flag={}", |
| 1021 | m_system_settings.bluetooth_enable_flag); | ||
| 918 | 1022 | ||
| 919 | LOG_WARNING(Service_SET, "(STUBBED) called, author_id={}", author_id.FormattedString()); | 1023 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1024 | rb.Push(ResultSuccess); | ||
| 1025 | rb.Push<u8>(m_system_settings.bluetooth_enable_flag); | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | void ISystemSettingsServer::SetBluetoothEnableFlag(HLERequestContext& ctx) { | ||
| 1029 | IPC::RequestParser rp{ctx}; | ||
| 1030 | m_system_settings.bluetooth_enable_flag = rp.Pop<bool>(); | ||
| 1031 | SetSaveNeeded(); | ||
| 1032 | |||
| 1033 | LOG_INFO(Service_SET, "called, bluetooth_enable_flag={}", | ||
| 1034 | m_system_settings.bluetooth_enable_flag); | ||
| 1035 | |||
| 1036 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1037 | rb.Push(ResultSuccess); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | void ISystemSettingsServer::GetMiiAuthorId(HLERequestContext& ctx) { | ||
| 1041 | LOG_INFO(Service_SET, "called, author_id={}", | ||
| 1042 | m_system_settings.mii_author_id.FormattedString()); | ||
| 920 | 1043 | ||
| 921 | IPC::ResponseBuilder rb{ctx, 6}; | 1044 | IPC::ResponseBuilder rb{ctx, 6}; |
| 922 | rb.Push(ResultSuccess); | 1045 | rb.Push(ResultSuccess); |
| 923 | rb.PushRaw(author_id); | 1046 | rb.PushRaw(m_system_settings.mii_author_id); |
| 924 | } | 1047 | } |
| 925 | 1048 | ||
| 926 | void ISystemSettingsServer::GetAutoUpdateEnableFlag(HLERequestContext& ctx) { | 1049 | void ISystemSettingsServer::GetAutoUpdateEnableFlag(HLERequestContext& ctx) { |
| 927 | u8 auto_update_flag{}; | 1050 | LOG_INFO(Service_SET, "called, auto_update_flag={}", m_system_settings.auto_update_enable_flag); |
| 928 | |||
| 929 | LOG_WARNING(Service_SET, "(STUBBED) called, auto_update_flag={}", auto_update_flag); | ||
| 930 | 1051 | ||
| 931 | IPC::ResponseBuilder rb{ctx, 3}; | 1052 | IPC::ResponseBuilder rb{ctx, 3}; |
| 932 | rb.Push(ResultSuccess); | 1053 | rb.Push(ResultSuccess); |
| 933 | rb.Push(auto_update_flag); | 1054 | rb.Push(m_system_settings.auto_update_enable_flag); |
| 934 | } | 1055 | } |
| 935 | 1056 | ||
| 936 | void ISystemSettingsServer::GetBatteryPercentageFlag(HLERequestContext& ctx) { | 1057 | void ISystemSettingsServer::GetBatteryPercentageFlag(HLERequestContext& ctx) { |
| 937 | u8 battery_percentage_flag{1}; | 1058 | LOG_DEBUG(Service_SET, "called, battery_percentage_flag={}", |
| 938 | 1059 | m_system_settings.battery_percentage_flag); | |
| 939 | LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}", | ||
| 940 | battery_percentage_flag); | ||
| 941 | 1060 | ||
| 942 | IPC::ResponseBuilder rb{ctx, 3}; | 1061 | IPC::ResponseBuilder rb{ctx, 3}; |
| 943 | rb.Push(ResultSuccess); | 1062 | rb.Push(ResultSuccess); |
| 944 | rb.Push(battery_percentage_flag); | 1063 | rb.Push(m_system_settings.battery_percentage_flag); |
| 945 | } | 1064 | } |
| 946 | 1065 | ||
| 947 | void ISystemSettingsServer::SetExternalSteadyClockInternalOffset(HLERequestContext& ctx) { | 1066 | void ISystemSettingsServer::SetExternalSteadyClockInternalOffset(HLERequestContext& ctx) { |
| @@ -968,11 +1087,12 @@ void ISystemSettingsServer::GetExternalSteadyClockInternalOffset(HLERequestConte | |||
| 968 | } | 1087 | } |
| 969 | 1088 | ||
| 970 | void ISystemSettingsServer::GetErrorReportSharePermission(HLERequestContext& ctx) { | 1089 | void ISystemSettingsServer::GetErrorReportSharePermission(HLERequestContext& ctx) { |
| 971 | LOG_WARNING(Service_SET, "(STUBBED) called"); | 1090 | LOG_INFO(Service_SET, "called, error_report_share_permission={}", |
| 1091 | m_system_settings.error_report_share_permission); | ||
| 972 | 1092 | ||
| 973 | IPC::ResponseBuilder rb{ctx, 3}; | 1093 | IPC::ResponseBuilder rb{ctx, 3}; |
| 974 | rb.Push(ResultSuccess); | 1094 | rb.Push(ResultSuccess); |
| 975 | rb.PushEnum(ErrorReportSharePermission::Denied); | 1095 | rb.PushEnum(m_system_settings.error_report_share_permission); |
| 976 | } | 1096 | } |
| 977 | 1097 | ||
| 978 | void ISystemSettingsServer::GetAppletLaunchFlags(HLERequestContext& ctx) { | 1098 | void ISystemSettingsServer::GetAppletLaunchFlags(HLERequestContext& ctx) { |
| @@ -1014,7 +1134,7 @@ void ISystemSettingsServer::GetKeyboardLayout(HLERequestContext& ctx) { | |||
| 1014 | } | 1134 | } |
| 1015 | 1135 | ||
| 1016 | void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { | 1136 | void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { |
| 1017 | LOG_WARNING(Service_SET, "called."); | 1137 | LOG_INFO(Service_SET, "called"); |
| 1018 | 1138 | ||
| 1019 | Service::Time::Clock::SteadyClockTimePoint time_point{}; | 1139 | Service::Time::Clock::SteadyClockTimePoint time_point{}; |
| 1020 | auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point); | 1140 | auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point); |
| @@ -1025,7 +1145,7 @@ void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestConte | |||
| 1025 | } | 1145 | } |
| 1026 | 1146 | ||
| 1027 | void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { | 1147 | void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { |
| 1028 | LOG_WARNING(Service_SET, "called."); | 1148 | LOG_INFO(Service_SET, "called"); |
| 1029 | 1149 | ||
| 1030 | IPC::RequestParser rp{ctx}; | 1150 | IPC::RequestParser rp{ctx}; |
| 1031 | auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; | 1151 | auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; |
| @@ -1038,7 +1158,7 @@ void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestConte | |||
| 1038 | 1158 | ||
| 1039 | void ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( | 1159 | void ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( |
| 1040 | HLERequestContext& ctx) { | 1160 | HLERequestContext& ctx) { |
| 1041 | LOG_WARNING(Service_SET, "called."); | 1161 | LOG_INFO(Service_SET, "called"); |
| 1042 | 1162 | ||
| 1043 | Service::Time::Clock::SteadyClockTimePoint time_point{}; | 1163 | Service::Time::Clock::SteadyClockTimePoint time_point{}; |
| 1044 | auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); | 1164 | auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); |
| @@ -1050,7 +1170,7 @@ void ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime( | |||
| 1050 | 1170 | ||
| 1051 | void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( | 1171 | void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( |
| 1052 | HLERequestContext& ctx) { | 1172 | HLERequestContext& ctx) { |
| 1053 | LOG_WARNING(Service_SET, "called."); | 1173 | LOG_INFO(Service_SET, "called"); |
| 1054 | 1174 | ||
| 1055 | IPC::RequestParser rp{ctx}; | 1175 | IPC::RequestParser rp{ctx}; |
| 1056 | auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; | 1176 | auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; |
| @@ -1062,11 +1182,12 @@ void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime( | |||
| 1062 | } | 1182 | } |
| 1063 | 1183 | ||
| 1064 | void ISystemSettingsServer::GetChineseTraditionalInputMethod(HLERequestContext& ctx) { | 1184 | void ISystemSettingsServer::GetChineseTraditionalInputMethod(HLERequestContext& ctx) { |
| 1065 | LOG_WARNING(Service_SET, "(STUBBED) called"); | 1185 | LOG_INFO(Service_SET, "called, chinese_traditional_input_method={}", |
| 1186 | m_system_settings.chinese_traditional_input_method); | ||
| 1066 | 1187 | ||
| 1067 | IPC::ResponseBuilder rb{ctx, 3}; | 1188 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1068 | rb.Push(ResultSuccess); | 1189 | rb.Push(ResultSuccess); |
| 1069 | rb.PushEnum(ChineseTraditionalInputMethod::Unknown0); | 1190 | rb.PushEnum(m_system_settings.chinese_traditional_input_method); |
| 1070 | } | 1191 | } |
| 1071 | 1192 | ||
| 1072 | void ISystemSettingsServer::GetHomeMenuScheme(HLERequestContext& ctx) { | 1193 | void ISystemSettingsServer::GetHomeMenuScheme(HLERequestContext& ctx) { |
| @@ -1094,11 +1215,11 @@ void ISystemSettingsServer::GetHomeMenuSchemeModel(HLERequestContext& ctx) { | |||
| 1094 | } | 1215 | } |
| 1095 | 1216 | ||
| 1096 | void ISystemSettingsServer::GetFieldTestingFlag(HLERequestContext& ctx) { | 1217 | void ISystemSettingsServer::GetFieldTestingFlag(HLERequestContext& ctx) { |
| 1097 | LOG_WARNING(Service_SET, "(STUBBED) called"); | 1218 | LOG_INFO(Service_SET, "called, field_testing_flag={}", m_system_settings.field_testing_flag); |
| 1098 | 1219 | ||
| 1099 | IPC::ResponseBuilder rb{ctx, 3}; | 1220 | IPC::ResponseBuilder rb{ctx, 3}; |
| 1100 | rb.Push(ResultSuccess); | 1221 | rb.Push(ResultSuccess); |
| 1101 | rb.Push<u8>(false); | 1222 | rb.Push(m_system_settings.field_testing_flag); |
| 1102 | } | 1223 | } |
| 1103 | 1224 | ||
| 1104 | void ISystemSettingsServer::SetupSettings() { | 1225 | void ISystemSettingsServer::SetupSettings() { |
diff --git a/src/core/hle/service/set/system_settings_server.h b/src/core/hle/service/set/system_settings_server.h index 6f587e0b3..32716f567 100644 --- a/src/core/hle/service/set/system_settings_server.h +++ b/src/core/hle/service/set/system_settings_server.h | |||
| @@ -12,10 +12,11 @@ | |||
| 12 | #include "common/uuid.h" | 12 | #include "common/uuid.h" |
| 13 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 14 | #include "core/hle/service/service.h" | 14 | #include "core/hle/service/service.h" |
| 15 | #include "core/hle/service/set/appln_settings.h" | 15 | #include "core/hle/service/set/setting_formats/appln_settings.h" |
| 16 | #include "core/hle/service/set/device_settings.h" | 16 | #include "core/hle/service/set/setting_formats/device_settings.h" |
| 17 | #include "core/hle/service/set/private_settings.h" | 17 | #include "core/hle/service/set/setting_formats/private_settings.h" |
| 18 | #include "core/hle/service/set/system_settings.h" | 18 | #include "core/hle/service/set/setting_formats/system_settings.h" |
| 19 | #include "core/hle/service/set/settings_types.h" | ||
| 19 | #include "core/hle/service/time/clock_types.h" | 20 | #include "core/hle/service/time/clock_types.h" |
| 20 | #include "core/hle/service/time/time_zone_types.h" | 21 | #include "core/hle/service/time/time_zone_types.h" |
| 21 | 22 | ||
| @@ -24,25 +25,6 @@ class System; | |||
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | namespace Service::Set { | 27 | namespace Service::Set { |
| 27 | enum class GetFirmwareVersionType { | ||
| 28 | Version1, | ||
| 29 | Version2, | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct FirmwareVersionFormat { | ||
| 33 | u8 major; | ||
| 34 | u8 minor; | ||
| 35 | u8 micro; | ||
| 36 | INSERT_PADDING_BYTES(1); | ||
| 37 | u8 revision_major; | ||
| 38 | u8 revision_minor; | ||
| 39 | INSERT_PADDING_BYTES(2); | ||
| 40 | std::array<char, 0x20> platform; | ||
| 41 | std::array<u8, 0x40> version_hash; | ||
| 42 | std::array<char, 0x18> display_version; | ||
| 43 | std::array<char, 0x80> display_title; | ||
| 44 | }; | ||
| 45 | static_assert(sizeof(FirmwareVersionFormat) == 0x100, "FirmwareVersionFormat is an invalid size"); | ||
| 46 | 28 | ||
| 47 | Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, | 29 | Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, |
| 48 | GetFirmwareVersionType type); | 30 | GetFirmwareVersionType type); |
| @@ -55,6 +37,18 @@ public: | |||
| 55 | Result GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category, | 37 | Result GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category, |
| 56 | const std::string& name); | 38 | const std::string& name); |
| 57 | 39 | ||
| 40 | template <typename T> | ||
| 41 | Result GetSettingsItemValue(T& value, const std::string& category, const std::string& name) { | ||
| 42 | std::vector<u8> data; | ||
| 43 | const auto result = GetSettingsItemValue(data, category, name); | ||
| 44 | if (result.IsError()) { | ||
| 45 | return result; | ||
| 46 | } | ||
| 47 | ASSERT(data.size() >= sizeof(T)); | ||
| 48 | std::memcpy(&value, data.data(), sizeof(T)); | ||
| 49 | return result; | ||
| 50 | } | ||
| 51 | |||
| 58 | Result GetExternalSteadyClockSourceId(Common::UUID& out_id); | 52 | Result GetExternalSteadyClockSourceId(Common::UUID& out_id); |
| 59 | Result SetExternalSteadyClockSourceId(Common::UUID id); | 53 | Result SetExternalSteadyClockSourceId(Common::UUID id); |
| 60 | Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); | 54 | Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); |
| @@ -80,6 +74,8 @@ private: | |||
| 80 | void SetLanguageCode(HLERequestContext& ctx); | 74 | void SetLanguageCode(HLERequestContext& ctx); |
| 81 | void GetFirmwareVersion(HLERequestContext& ctx); | 75 | void GetFirmwareVersion(HLERequestContext& ctx); |
| 82 | void GetFirmwareVersion2(HLERequestContext& ctx); | 76 | void GetFirmwareVersion2(HLERequestContext& ctx); |
| 77 | void GetLockScreenFlag(HLERequestContext& ctx); | ||
| 78 | void SetLockScreenFlag(HLERequestContext& ctx); | ||
| 83 | void GetExternalSteadyClockSourceId(HLERequestContext& ctx); | 79 | void GetExternalSteadyClockSourceId(HLERequestContext& ctx); |
| 84 | void SetExternalSteadyClockSourceId(HLERequestContext& ctx); | 80 | void SetExternalSteadyClockSourceId(HLERequestContext& ctx); |
| 85 | void GetUserSystemClockContext(HLERequestContext& ctx); | 81 | void GetUserSystemClockContext(HLERequestContext& ctx); |
| @@ -108,13 +104,19 @@ private: | |||
| 108 | void IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); | 104 | void IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); |
| 109 | void SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); | 105 | void SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); |
| 110 | void GetPrimaryAlbumStorage(HLERequestContext& ctx); | 106 | void GetPrimaryAlbumStorage(HLERequestContext& ctx); |
| 107 | void GetNfcEnableFlag(HLERequestContext& ctx); | ||
| 108 | void SetNfcEnableFlag(HLERequestContext& ctx); | ||
| 111 | void GetSleepSettings(HLERequestContext& ctx); | 109 | void GetSleepSettings(HLERequestContext& ctx); |
| 112 | void SetSleepSettings(HLERequestContext& ctx); | 110 | void SetSleepSettings(HLERequestContext& ctx); |
| 111 | void GetWirelessLanEnableFlag(HLERequestContext& ctx); | ||
| 112 | void SetWirelessLanEnableFlag(HLERequestContext& ctx); | ||
| 113 | void GetInitialLaunchSettings(HLERequestContext& ctx); | 113 | void GetInitialLaunchSettings(HLERequestContext& ctx); |
| 114 | void SetInitialLaunchSettings(HLERequestContext& ctx); | 114 | void SetInitialLaunchSettings(HLERequestContext& ctx); |
| 115 | void GetDeviceNickName(HLERequestContext& ctx); | 115 | void GetDeviceNickName(HLERequestContext& ctx); |
| 116 | void SetDeviceNickName(HLERequestContext& ctx); | 116 | void SetDeviceNickName(HLERequestContext& ctx); |
| 117 | void GetProductModel(HLERequestContext& ctx); | 117 | void GetProductModel(HLERequestContext& ctx); |
| 118 | void GetBluetoothEnableFlag(HLERequestContext& ctx); | ||
| 119 | void SetBluetoothEnableFlag(HLERequestContext& ctx); | ||
| 118 | void GetMiiAuthorId(HLERequestContext& ctx); | 120 | void GetMiiAuthorId(HLERequestContext& ctx); |
| 119 | void GetAutoUpdateEnableFlag(HLERequestContext& ctx); | 121 | void GetAutoUpdateEnableFlag(HLERequestContext& ctx); |
| 120 | void GetBatteryPercentageFlag(HLERequestContext& ctx); | 122 | void GetBatteryPercentageFlag(HLERequestContext& ctx); |
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index e2d9cd98a..725311c53 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp | |||
| @@ -91,6 +91,10 @@ void Display::CreateLayer(u64 layer_id, u32 binder_id, | |||
| 91 | layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer, | 91 | layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer, |
| 92 | std::move(buffer_item_consumer))); | 92 | std::move(buffer_item_consumer))); |
| 93 | 93 | ||
| 94 | if (is_abandoned) { | ||
| 95 | this->FindLayer(layer_id)->GetConsumer().Abandon(); | ||
| 96 | } | ||
| 97 | |||
| 94 | hos_binder_driver_server.RegisterProducer(std::move(producer)); | 98 | hos_binder_driver_server.RegisterProducer(std::move(producer)); |
| 95 | } | 99 | } |
| 96 | 100 | ||
| @@ -103,6 +107,13 @@ void Display::DestroyLayer(u64 layer_id) { | |||
| 103 | [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; }); | 107 | [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; }); |
| 104 | } | 108 | } |
| 105 | 109 | ||
| 110 | void Display::Abandon() { | ||
| 111 | for (auto& layer : layers) { | ||
| 112 | layer->GetConsumer().Abandon(); | ||
| 113 | } | ||
| 114 | is_abandoned = true; | ||
| 115 | } | ||
| 116 | |||
| 106 | Layer* Display::FindLayer(u64 layer_id) { | 117 | Layer* Display::FindLayer(u64 layer_id) { |
| 107 | const auto itr = | 118 | const auto itr = |
| 108 | std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) { | 119 | std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) { |
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 7e68ee79b..8eb8a5155 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h | |||
| @@ -98,6 +98,8 @@ public: | |||
| 98 | layers.clear(); | 98 | layers.clear(); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void Abandon(); | ||
| 102 | |||
| 101 | /// Attempts to find a layer with the given ID. | 103 | /// Attempts to find a layer with the given ID. |
| 102 | /// | 104 | /// |
| 103 | /// @param layer_id The layer ID. | 105 | /// @param layer_id The layer ID. |
| @@ -124,6 +126,7 @@ private: | |||
| 124 | 126 | ||
| 125 | std::vector<std::unique_ptr<Layer>> layers; | 127 | std::vector<std::unique_ptr<Layer>> layers; |
| 126 | Kernel::KEvent* vsync_event{}; | 128 | Kernel::KEvent* vsync_event{}; |
| 129 | bool is_abandoned{}; | ||
| 127 | }; | 130 | }; |
| 128 | 131 | ||
| 129 | } // namespace Service::VI | 132 | } // namespace Service::VI |
diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h index 295005e23..f95e2dc71 100644 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ b/src/core/hle/service/vi/layer/vi_layer.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <utility> | ||
| 7 | 8 | ||
| 8 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 9 | 10 | ||
| @@ -75,12 +76,12 @@ public: | |||
| 75 | return open; | 76 | return open; |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | void Close() { | 79 | bool Close() { |
| 79 | open = false; | 80 | return std::exchange(open, false); |
| 80 | } | 81 | } |
| 81 | 82 | ||
| 82 | void Open() { | 83 | bool Open() { |
| 83 | open = true; | 84 | return !std::exchange(open, true); |
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | private: | 87 | private: |
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 39d5be90d..bfcc27ddc 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -719,7 +719,12 @@ private: | |||
| 719 | return; | 719 | return; |
| 720 | } | 720 | } |
| 721 | 721 | ||
| 722 | nvnflinger.OpenLayer(layer_id); | 722 | if (!nvnflinger.OpenLayer(layer_id)) { |
| 723 | LOG_WARNING(Service_VI, "Tried to open layer which was already open"); | ||
| 724 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 725 | rb.Push(ResultOperationFailed); | ||
| 726 | return; | ||
| 727 | } | ||
| 723 | 728 | ||
| 724 | android::OutputParcel parcel; | 729 | android::OutputParcel parcel; |
| 725 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); | 730 | parcel.WriteInterface(NativeWindow{*buffer_queue_id}); |
| @@ -737,7 +742,12 @@ private: | |||
| 737 | 742 | ||
| 738 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); | 743 | LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); |
| 739 | 744 | ||
| 740 | nvnflinger.CloseLayer(layer_id); | 745 | if (!nvnflinger.CloseLayer(layer_id)) { |
| 746 | LOG_WARNING(Service_VI, "Tried to close layer which was not open"); | ||
| 747 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 748 | rb.Push(ResultOperationFailed); | ||
| 749 | return; | ||
| 750 | } | ||
| 741 | 751 | ||
| 742 | IPC::ResponseBuilder rb{ctx, 2}; | 752 | IPC::ResponseBuilder rb{ctx, 2}; |
| 743 | rb.Push(ResultSuccess); | 753 | rb.Push(ResultSuccess); |
diff --git a/src/frontend_common/CMakeLists.txt b/src/frontend_common/CMakeLists.txt index 22e9337c4..94d8cc4c3 100644 --- a/src/frontend_common/CMakeLists.txt +++ b/src/frontend_common/CMakeLists.txt | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | add_library(frontend_common STATIC | 4 | add_library(frontend_common STATIC |
| 5 | config.cpp | 5 | config.cpp |
| 6 | config.h | 6 | config.h |
| 7 | content_manager.h | ||
| 7 | ) | 8 | ) |
| 8 | 9 | ||
| 9 | create_target_directory_groups(frontend_common) | 10 | create_target_directory_groups(frontend_common) |
diff --git a/src/frontend_common/config.cpp b/src/frontend_common/config.cpp index 9eb4799a6..46277e288 100644 --- a/src/frontend_common/config.cpp +++ b/src/frontend_common/config.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <array> | 5 | #include <array> |
| 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 "common/logging/log.h" | ||
| 8 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 9 | #include "common/settings_common.h" | 10 | #include "common/settings_common.h" |
| 10 | #include "common/settings_enums.h" | 11 | #include "common/settings_enums.h" |
| @@ -58,6 +59,19 @@ void Config::Initialize(const std::optional<std::string> config_path) { | |||
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | void Config::WriteToIni() const { | 61 | void Config::WriteToIni() const { |
| 62 | std::string config_type; | ||
| 63 | switch (type) { | ||
| 64 | case ConfigType::GlobalConfig: | ||
| 65 | config_type = "Global"; | ||
| 66 | break; | ||
| 67 | case ConfigType::PerGameConfig: | ||
| 68 | config_type = "Game Specific"; | ||
| 69 | break; | ||
| 70 | case ConfigType::InputProfile: | ||
| 71 | config_type = "Input Profile"; | ||
| 72 | break; | ||
| 73 | } | ||
| 74 | LOG_INFO(Config, "Writing {} configuration to: {}", config_type, config_loc); | ||
| 61 | FILE* fp = nullptr; | 75 | FILE* fp = nullptr; |
| 62 | #ifdef _WIN32 | 76 | #ifdef _WIN32 |
| 63 | fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb"); | 77 | fp = _wfopen(Common::UTF8ToUTF16W(config_loc).data(), L"wb"); |
| @@ -117,10 +131,10 @@ void Config::ReadPlayerValues(const std::size_t player_index) { | |||
| 117 | player_prefix.append("player_").append(ToString(player_index)).append("_"); | 131 | player_prefix.append("player_").append(ToString(player_index)).append("_"); |
| 118 | } | 132 | } |
| 119 | 133 | ||
| 134 | const auto profile_name = ReadStringSetting(std::string(player_prefix).append("profile_name")); | ||
| 135 | |||
| 120 | auto& player = Settings::values.players.GetValue()[player_index]; | 136 | auto& player = Settings::values.players.GetValue()[player_index]; |
| 121 | if (IsCustomConfig()) { | 137 | if (IsCustomConfig()) { |
| 122 | const auto profile_name = | ||
| 123 | ReadStringSetting(std::string(player_prefix).append("profile_name")); | ||
| 124 | if (profile_name.empty()) { | 138 | if (profile_name.empty()) { |
| 125 | // Use the global input config | 139 | // Use the global input config |
| 126 | player = Settings::values.players.GetValue(true)[player_index]; | 140 | player = Settings::values.players.GetValue(true)[player_index]; |
| @@ -139,6 +153,10 @@ void Config::ReadPlayerValues(const std::size_t player_index) { | |||
| 139 | player.controller_type = controller; | 153 | player.controller_type = controller; |
| 140 | } | 154 | } |
| 141 | } else { | 155 | } else { |
| 156 | if (global) { | ||
| 157 | auto& player_global = Settings::values.players.GetValue(true)[player_index]; | ||
| 158 | player_global.profile_name = profile_name; | ||
| 159 | } | ||
| 142 | std::string connected_key = player_prefix; | 160 | std::string connected_key = player_prefix; |
| 143 | player.connected = ReadBooleanSetting(connected_key.append("connected"), | 161 | player.connected = ReadBooleanSetting(connected_key.append("connected"), |
| 144 | std::make_optional(player_index == 0)); | 162 | std::make_optional(player_index == 0)); |
| @@ -412,6 +430,11 @@ void Config::SavePlayerValues(const std::size_t player_index) { | |||
| 412 | std::make_optional(static_cast<u8>(Settings::ControllerType::ProController))); | 430 | std::make_optional(static_cast<u8>(Settings::ControllerType::ProController))); |
| 413 | 431 | ||
| 414 | if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) { | 432 | if (!player_prefix.empty() || !Settings::IsConfiguringGlobal()) { |
| 433 | if (global) { | ||
| 434 | const auto& player_global = Settings::values.players.GetValue(true)[player_index]; | ||
| 435 | WriteStringSetting(std::string(player_prefix).append("profile_name"), | ||
| 436 | player_global.profile_name, std::make_optional(std::string(""))); | ||
| 437 | } | ||
| 415 | WriteBooleanSetting(std::string(player_prefix).append("connected"), player.connected, | 438 | WriteBooleanSetting(std::string(player_prefix).append("connected"), player.connected, |
| 416 | std::make_optional(player_index == 0)); | 439 | std::make_optional(player_index == 0)); |
| 417 | WriteIntegerSetting(std::string(player_prefix).append("vibration_enabled"), | 440 | WriteIntegerSetting(std::string(player_prefix).append("vibration_enabled"), |
| @@ -468,12 +491,15 @@ void Config::SaveMotionTouchValues() { | |||
| 468 | 491 | ||
| 469 | void Config::SaveValues() { | 492 | void Config::SaveValues() { |
| 470 | if (global) { | 493 | if (global) { |
| 494 | LOG_DEBUG(Config, "Saving global generic configuration values"); | ||
| 471 | SaveDataStorageValues(); | 495 | SaveDataStorageValues(); |
| 472 | SaveDebuggingValues(); | 496 | SaveDebuggingValues(); |
| 473 | SaveDisabledAddOnValues(); | 497 | SaveDisabledAddOnValues(); |
| 474 | SaveNetworkValues(); | 498 | SaveNetworkValues(); |
| 475 | SaveWebServiceValues(); | 499 | SaveWebServiceValues(); |
| 476 | SaveMiscellaneousValues(); | 500 | SaveMiscellaneousValues(); |
| 501 | } else { | ||
| 502 | LOG_DEBUG(Config, "Saving only generic configuration values"); | ||
| 477 | } | 503 | } |
| 478 | SaveControlValues(); | 504 | SaveControlValues(); |
| 479 | SaveCoreValues(); | 505 | SaveCoreValues(); |
| @@ -814,10 +840,6 @@ void Config::Reload() { | |||
| 814 | SaveValues(); | 840 | SaveValues(); |
| 815 | } | 841 | } |
| 816 | 842 | ||
| 817 | void Config::Save() { | ||
| 818 | SaveValues(); | ||
| 819 | } | ||
| 820 | |||
| 821 | void Config::ClearControlPlayerValues() const { | 843 | void Config::ClearControlPlayerValues() const { |
| 822 | // If key is an empty string, all keys in the current group() are removed. | 844 | // If key is an empty string, all keys in the current group() are removed. |
| 823 | const char* section = Settings::TranslateCategory(Settings::Category::Controls); | 845 | const char* section = Settings::TranslateCategory(Settings::Category::Controls); |
diff --git a/src/frontend_common/config.h b/src/frontend_common/config.h index b01631649..4798d6432 100644 --- a/src/frontend_common/config.h +++ b/src/frontend_common/config.h | |||
| @@ -51,7 +51,6 @@ protected: | |||
| 51 | [[nodiscard]] bool IsCustomConfig() const; | 51 | [[nodiscard]] bool IsCustomConfig() const; |
| 52 | 52 | ||
| 53 | void Reload(); | 53 | void Reload(); |
| 54 | void Save(); | ||
| 55 | 54 | ||
| 56 | /** | 55 | /** |
| 57 | * Derived config classes must implement this so they can reload all platform-specific | 56 | * Derived config classes must implement this so they can reload all platform-specific |
diff --git a/src/frontend_common/content_manager.h b/src/frontend_common/content_manager.h new file mode 100644 index 000000000..23f2979db --- /dev/null +++ b/src/frontend_common/content_manager.h | |||
| @@ -0,0 +1,238 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <boost/algorithm/string.hpp> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/literals.h" | ||
| 9 | #include "core/core.h" | ||
| 10 | #include "core/file_sys/common_funcs.h" | ||
| 11 | #include "core/file_sys/content_archive.h" | ||
| 12 | #include "core/file_sys/mode.h" | ||
| 13 | #include "core/file_sys/nca_metadata.h" | ||
| 14 | #include "core/file_sys/registered_cache.h" | ||
| 15 | #include "core/file_sys/submission_package.h" | ||
| 16 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 17 | #include "core/loader/loader.h" | ||
| 18 | |||
| 19 | namespace ContentManager { | ||
| 20 | |||
| 21 | enum class InstallResult { | ||
| 22 | Success, | ||
| 23 | Overwrite, | ||
| 24 | Failure, | ||
| 25 | BaseInstallAttempted, | ||
| 26 | }; | ||
| 27 | |||
| 28 | /** | ||
| 29 | * \brief Removes a single installed DLC | ||
| 30 | * \param fs_controller [FileSystemController] reference from the Core::System instance | ||
| 31 | * \param title_id Unique title ID representing the DLC which will be removed | ||
| 32 | * \return 'true' if successful | ||
| 33 | */ | ||
| 34 | inline bool RemoveDLC(const Service::FileSystem::FileSystemController& fs_controller, | ||
| 35 | const u64 title_id) { | ||
| 36 | return fs_controller.GetUserNANDContents()->RemoveExistingEntry(title_id) || | ||
| 37 | fs_controller.GetSDMCContents()->RemoveExistingEntry(title_id); | ||
| 38 | } | ||
| 39 | |||
| 40 | /** | ||
| 41 | * \brief Removes all DLC for a game | ||
| 42 | * \param system Raw pointer to the system instance | ||
| 43 | * \param program_id Program ID for the game that will have all of its DLC removed | ||
| 44 | * \return Number of DLC removed | ||
| 45 | */ | ||
| 46 | inline size_t RemoveAllDLC(Core::System* system, const u64 program_id) { | ||
| 47 | size_t count{}; | ||
| 48 | const auto& fs_controller = system->GetFileSystemController(); | ||
| 49 | const auto dlc_entries = system->GetContentProvider().ListEntriesFilter( | ||
| 50 | FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); | ||
| 51 | std::vector<u64> program_dlc_entries; | ||
| 52 | |||
| 53 | for (const auto& entry : dlc_entries) { | ||
| 54 | if (FileSys::GetBaseTitleID(entry.title_id) == program_id) { | ||
| 55 | program_dlc_entries.push_back(entry.title_id); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | for (const auto& entry : program_dlc_entries) { | ||
| 60 | if (RemoveDLC(fs_controller, entry)) { | ||
| 61 | ++count; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | return count; | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * \brief Removes the installed update for a game | ||
| 69 | * \param fs_controller [FileSystemController] reference from the Core::System instance | ||
| 70 | * \param program_id Program ID for the game that will have its installed update removed | ||
| 71 | * \return 'true' if successful | ||
| 72 | */ | ||
| 73 | inline bool RemoveUpdate(const Service::FileSystem::FileSystemController& fs_controller, | ||
| 74 | const u64 program_id) { | ||
| 75 | const auto update_id = program_id | 0x800; | ||
| 76 | return fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) || | ||
| 77 | fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id); | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * \brief Removes the base content for a game | ||
| 82 | * \param fs_controller [FileSystemController] reference from the Core::System instance | ||
| 83 | * \param program_id Program ID for the game that will have its base content removed | ||
| 84 | * \return 'true' if successful | ||
| 85 | */ | ||
| 86 | inline bool RemoveBaseContent(const Service::FileSystem::FileSystemController& fs_controller, | ||
| 87 | const u64 program_id) { | ||
| 88 | return fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) || | ||
| 89 | fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id); | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * \brief Removes a mod for a game | ||
| 94 | * \param fs_controller [FileSystemController] reference from the Core::System instance | ||
| 95 | * \param program_id Program ID for the game where [mod_name] will be removed | ||
| 96 | * \param mod_name The name of a mod as given by FileSys::PatchManager::GetPatches. This corresponds | ||
| 97 | * with the name of the mod's directory in a game's load folder. | ||
| 98 | * \return 'true' if successful | ||
| 99 | */ | ||
| 100 | inline bool RemoveMod(const Service::FileSystem::FileSystemController& fs_controller, | ||
| 101 | const u64 program_id, const std::string& mod_name) { | ||
| 102 | // Check general Mods (LayeredFS and IPS) | ||
| 103 | const auto mod_dir = fs_controller.GetModificationLoadRoot(program_id); | ||
| 104 | if (mod_dir != nullptr) { | ||
| 105 | return mod_dir->DeleteSubdirectoryRecursive(mod_name); | ||
| 106 | } | ||
| 107 | |||
| 108 | // Check SDMC mod directory (RomFS LayeredFS) | ||
| 109 | const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(program_id); | ||
| 110 | if (sdmc_mod_dir != nullptr) { | ||
| 111 | return sdmc_mod_dir->DeleteSubdirectoryRecursive(mod_name); | ||
| 112 | } | ||
| 113 | |||
| 114 | return false; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * \brief Installs an NSP | ||
| 119 | * \param system Raw pointer to the system instance | ||
| 120 | * \param vfs Raw pointer to the VfsFilesystem instance in Core::System | ||
| 121 | * \param filename Path to the NSP file | ||
| 122 | * \param callback Optional callback to report the progress of the installation. The first size_t | ||
| 123 | * parameter is the total size of the virtual file and the second is the current progress. If you | ||
| 124 | * return false to the callback, it will cancel the installation as soon as possible. | ||
| 125 | * \return [InstallResult] representing how the installation finished | ||
| 126 | */ | ||
| 127 | inline InstallResult InstallNSP( | ||
| 128 | Core::System* system, FileSys::VfsFilesystem* vfs, const std::string& filename, | ||
| 129 | const std::function<bool(size_t, size_t)>& callback = std::function<bool(size_t, size_t)>()) { | ||
| 130 | const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, | ||
| 131 | std::size_t block_size) { | ||
| 132 | if (src == nullptr || dest == nullptr) { | ||
| 133 | return false; | ||
| 134 | } | ||
| 135 | if (!dest->Resize(src->GetSize())) { | ||
| 136 | return false; | ||
| 137 | } | ||
| 138 | |||
| 139 | using namespace Common::Literals; | ||
| 140 | std::vector<u8> buffer(1_MiB); | ||
| 141 | |||
| 142 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { | ||
| 143 | if (callback(src->GetSize(), i)) { | ||
| 144 | dest->Resize(0); | ||
| 145 | return false; | ||
| 146 | } | ||
| 147 | const auto read = src->Read(buffer.data(), buffer.size(), i); | ||
| 148 | dest->Write(buffer.data(), read, i); | ||
| 149 | } | ||
| 150 | return true; | ||
| 151 | }; | ||
| 152 | |||
| 153 | std::shared_ptr<FileSys::NSP> nsp; | ||
| 154 | FileSys::VirtualFile file = vfs->OpenFile(filename, FileSys::Mode::Read); | ||
| 155 | if (boost::to_lower_copy(file->GetName()).ends_with(std::string("nsp"))) { | ||
| 156 | nsp = std::make_shared<FileSys::NSP>(file); | ||
| 157 | if (nsp->IsExtractedType()) { | ||
| 158 | return InstallResult::Failure; | ||
| 159 | } | ||
| 160 | } else { | ||
| 161 | return InstallResult::Failure; | ||
| 162 | } | ||
| 163 | |||
| 164 | if (nsp->GetStatus() != Loader::ResultStatus::Success) { | ||
| 165 | return InstallResult::Failure; | ||
| 166 | } | ||
| 167 | const auto res = | ||
| 168 | system->GetFileSystemController().GetUserNANDContents()->InstallEntry(*nsp, true, copy); | ||
| 169 | switch (res) { | ||
| 170 | case FileSys::InstallResult::Success: | ||
| 171 | return InstallResult::Success; | ||
| 172 | case FileSys::InstallResult::OverwriteExisting: | ||
| 173 | return InstallResult::Overwrite; | ||
| 174 | case FileSys::InstallResult::ErrorBaseInstall: | ||
| 175 | return InstallResult::BaseInstallAttempted; | ||
| 176 | default: | ||
| 177 | return InstallResult::Failure; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | /** | ||
| 182 | * \brief Installs an NCA | ||
| 183 | * \param vfs Raw pointer to the VfsFilesystem instance in Core::System | ||
| 184 | * \param filename Path to the NCA file | ||
| 185 | * \param registered_cache Raw pointer to the registered cache that the NCA will be installed to | ||
| 186 | * \param title_type Type of NCA package to install | ||
| 187 | * \param callback Optional callback to report the progress of the installation. The first size_t | ||
| 188 | * parameter is the total size of the virtual file and the second is the current progress. If you | ||
| 189 | * return false to the callback, it will cancel the installation as soon as possible. | ||
| 190 | * \return [InstallResult] representing how the installation finished | ||
| 191 | */ | ||
| 192 | inline InstallResult InstallNCA( | ||
| 193 | FileSys::VfsFilesystem* vfs, const std::string& filename, | ||
| 194 | FileSys::RegisteredCache* registered_cache, const FileSys::TitleType title_type, | ||
| 195 | const std::function<bool(size_t, size_t)>& callback = std::function<bool(size_t, size_t)>()) { | ||
| 196 | const auto copy = [callback](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, | ||
| 197 | std::size_t block_size) { | ||
| 198 | if (src == nullptr || dest == nullptr) { | ||
| 199 | return false; | ||
| 200 | } | ||
| 201 | if (!dest->Resize(src->GetSize())) { | ||
| 202 | return false; | ||
| 203 | } | ||
| 204 | |||
| 205 | using namespace Common::Literals; | ||
| 206 | std::vector<u8> buffer(1_MiB); | ||
| 207 | |||
| 208 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { | ||
| 209 | if (callback(src->GetSize(), i)) { | ||
| 210 | dest->Resize(0); | ||
| 211 | return false; | ||
| 212 | } | ||
| 213 | const auto read = src->Read(buffer.data(), buffer.size(), i); | ||
| 214 | dest->Write(buffer.data(), read, i); | ||
| 215 | } | ||
| 216 | return true; | ||
| 217 | }; | ||
| 218 | |||
| 219 | const auto nca = std::make_shared<FileSys::NCA>(vfs->OpenFile(filename, FileSys::Mode::Read)); | ||
| 220 | const auto id = nca->GetStatus(); | ||
| 221 | |||
| 222 | // Game updates necessary are missing base RomFS | ||
| 223 | if (id != Loader::ResultStatus::Success && | ||
| 224 | id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { | ||
| 225 | return InstallResult::Failure; | ||
| 226 | } | ||
| 227 | |||
| 228 | const auto res = registered_cache->InstallEntry(*nca, title_type, true, copy); | ||
| 229 | if (res == FileSys::InstallResult::Success) { | ||
| 230 | return InstallResult::Success; | ||
| 231 | } else if (res == FileSys::InstallResult::OverwriteExisting) { | ||
| 232 | return InstallResult::Overwrite; | ||
| 233 | } else { | ||
| 234 | return InstallResult::Failure; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | } // namespace ContentManager | ||
diff --git a/src/hid_core/frontend/emulated_controller.cpp b/src/hid_core/frontend/emulated_controller.cpp index 2ab93402d..f2499502d 100644 --- a/src/hid_core/frontend/emulated_controller.cpp +++ b/src/hid_core/frontend/emulated_controller.cpp | |||
| @@ -110,6 +110,7 @@ void EmulatedController::ReloadFromSettings() { | |||
| 110 | original_npad_type = npad_type; | 110 | original_npad_type = npad_type; |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::Active); | ||
| 113 | Disconnect(); | 114 | Disconnect(); |
| 114 | if (player.connected) { | 115 | if (player.connected) { |
| 115 | Connect(); | 116 | Connect(); |
| @@ -144,8 +145,8 @@ void EmulatedController::ReloadColorsFromSettings() { | |||
| 144 | 145 | ||
| 145 | void EmulatedController::LoadDevices() { | 146 | void EmulatedController::LoadDevices() { |
| 146 | // TODO(german77): Use more buttons to detect the correct device | 147 | // TODO(german77): Use more buttons to detect the correct device |
| 147 | const auto left_joycon = button_params[Settings::NativeButton::DRight]; | 148 | const auto& left_joycon = button_params[Settings::NativeButton::DRight]; |
| 148 | const auto right_joycon = button_params[Settings::NativeButton::A]; | 149 | const auto& right_joycon = button_params[Settings::NativeButton::A]; |
| 149 | 150 | ||
| 150 | // Triggers for GC controllers | 151 | // Triggers for GC controllers |
| 151 | trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; | 152 | trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; |
| @@ -1208,20 +1209,43 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { | |||
| 1208 | controller.nfc_state = controller.nfc_values; | 1209 | controller.nfc_state = controller.nfc_values; |
| 1209 | } | 1210 | } |
| 1210 | 1211 | ||
| 1211 | bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { | 1212 | bool EmulatedController::SetVibration(bool should_vibrate) { |
| 1213 | VibrationValue vibration_value = DEFAULT_VIBRATION_VALUE; | ||
| 1214 | if (should_vibrate) { | ||
| 1215 | vibration_value.high_amplitude = 1.0f; | ||
| 1216 | vibration_value.low_amplitude = 1.0f; | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | return SetVibration(DeviceIndex::Left, vibration_value); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | bool EmulatedController::SetVibration(u32 slot, Core::HID::VibrationGcErmCommand erm_command) { | ||
| 1223 | VibrationValue vibration_value = DEFAULT_VIBRATION_VALUE; | ||
| 1224 | if (erm_command == Core::HID::VibrationGcErmCommand::Start) { | ||
| 1225 | vibration_value.high_amplitude = 1.0f; | ||
| 1226 | vibration_value.low_amplitude = 1.0f; | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | return SetVibration(DeviceIndex::Left, vibration_value); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | bool EmulatedController::SetVibration(DeviceIndex device_index, const VibrationValue& vibration) { | ||
| 1212 | if (!is_initialized) { | 1233 | if (!is_initialized) { |
| 1213 | return false; | 1234 | return false; |
| 1214 | } | 1235 | } |
| 1215 | if (device_index >= output_devices.size()) { | 1236 | if (device_index >= DeviceIndex::MaxDeviceIndex) { |
| 1216 | return false; | 1237 | return false; |
| 1217 | } | 1238 | } |
| 1218 | if (!output_devices[device_index]) { | 1239 | const std::size_t index = static_cast<std::size_t>(device_index); |
| 1240 | if (!output_devices[index]) { | ||
| 1219 | return false; | 1241 | return false; |
| 1220 | } | 1242 | } |
| 1221 | const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); | 1243 | const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type); |
| 1222 | const auto& player = Settings::values.players.GetValue()[player_index]; | 1244 | const auto& player = Settings::values.players.GetValue()[player_index]; |
| 1223 | const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f; | 1245 | const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f; |
| 1224 | 1246 | ||
| 1247 | last_vibration_value = vibration; | ||
| 1248 | |||
| 1225 | if (!player.vibration_enabled) { | 1249 | if (!player.vibration_enabled) { |
| 1226 | return false; | 1250 | return false; |
| 1227 | } | 1251 | } |
| @@ -1239,8 +1263,11 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v | |||
| 1239 | .high_frequency = vibration.high_frequency, | 1263 | .high_frequency = vibration.high_frequency, |
| 1240 | .type = type, | 1264 | .type = type, |
| 1241 | }; | 1265 | }; |
| 1242 | return output_devices[device_index]->SetVibration(status) == | 1266 | return output_devices[index]->SetVibration(status) == Common::Input::DriverResult::Success; |
| 1243 | Common::Input::DriverResult::Success; | 1267 | } |
| 1268 | |||
| 1269 | VibrationValue EmulatedController::GetActualVibrationValue(DeviceIndex device_index) const { | ||
| 1270 | return last_vibration_value; | ||
| 1244 | } | 1271 | } |
| 1245 | 1272 | ||
| 1246 | bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { | 1273 | bool EmulatedController::IsVibrationEnabled(std::size_t device_index) { |
diff --git a/src/hid_core/frontend/emulated_controller.h b/src/hid_core/frontend/emulated_controller.h index 90e536e07..168abe089 100644 --- a/src/hid_core/frontend/emulated_controller.h +++ b/src/hid_core/frontend/emulated_controller.h | |||
| @@ -356,10 +356,27 @@ public: | |||
| 356 | const NfcState& GetNfc() const; | 356 | const NfcState& GetNfc() const; |
| 357 | 357 | ||
| 358 | /** | 358 | /** |
| 359 | * Sends an on/off vibration to the left device | ||
| 360 | * @return true if vibration had no errors | ||
| 361 | */ | ||
| 362 | bool SetVibration(bool should_vibrate); | ||
| 363 | |||
| 364 | /** | ||
| 365 | * Sends an GC vibration to the left device | ||
| 366 | * @return true if vibration had no errors | ||
| 367 | */ | ||
| 368 | bool SetVibration(u32 slot, Core::HID::VibrationGcErmCommand erm_command); | ||
| 369 | |||
| 370 | /** | ||
| 359 | * Sends a specific vibration to the output device | 371 | * Sends a specific vibration to the output device |
| 360 | * @return true if vibration had no errors | 372 | * @return true if vibration had no errors |
| 361 | */ | 373 | */ |
| 362 | bool SetVibration(std::size_t device_index, VibrationValue vibration); | 374 | bool SetVibration(DeviceIndex device_index, const VibrationValue& vibration); |
| 375 | |||
| 376 | /** | ||
| 377 | * @return The last sent vibration | ||
| 378 | */ | ||
| 379 | VibrationValue GetActualVibrationValue(DeviceIndex device_index) const; | ||
| 363 | 380 | ||
| 364 | /** | 381 | /** |
| 365 | * Sends a small vibration to the output device | 382 | * Sends a small vibration to the output device |
| @@ -564,6 +581,7 @@ private: | |||
| 564 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; | 581 | f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; |
| 565 | u32 turbo_button_state{0}; | 582 | u32 turbo_button_state{0}; |
| 566 | std::size_t nfc_handles{0}; | 583 | std::size_t nfc_handles{0}; |
| 584 | VibrationValue last_vibration_value{DEFAULT_VIBRATION_VALUE}; | ||
| 567 | 585 | ||
| 568 | // Temporary values to avoid doing changes while the controller is in configuring mode | 586 | // Temporary values to avoid doing changes while the controller is in configuring mode |
| 569 | NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; | 587 | NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; |
diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp index 2c5fe6d51..ca824b4a3 100644 --- a/src/hid_core/resource_manager.cpp +++ b/src/hid_core/resource_manager.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "core/hle/kernel/k_shared_memory.h" | 7 | #include "core/hle/kernel/k_shared_memory.h" |
| 8 | #include "core/hle/service/ipc_helpers.h" | 8 | #include "core/hle/service/ipc_helpers.h" |
| 9 | #include "hid_core/hid_core.h" | 9 | #include "hid_core/hid_core.h" |
| 10 | #include "hid_core/hid_util.h" | ||
| 10 | #include "hid_core/resource_manager.h" | 11 | #include "hid_core/resource_manager.h" |
| 11 | 12 | ||
| 12 | #include "hid_core/resources/applet_resource.h" | 13 | #include "hid_core/resources/applet_resource.h" |
| @@ -27,6 +28,10 @@ | |||
| 27 | #include "hid_core/resources/touch_screen/gesture.h" | 28 | #include "hid_core/resources/touch_screen/gesture.h" |
| 28 | #include "hid_core/resources/touch_screen/touch_screen.h" | 29 | #include "hid_core/resources/touch_screen/touch_screen.h" |
| 29 | #include "hid_core/resources/unique_pad/unique_pad.h" | 30 | #include "hid_core/resources/unique_pad/unique_pad.h" |
| 31 | #include "hid_core/resources/vibration/gc_vibration_device.h" | ||
| 32 | #include "hid_core/resources/vibration/n64_vibration_device.h" | ||
| 33 | #include "hid_core/resources/vibration/vibration_base.h" | ||
| 34 | #include "hid_core/resources/vibration/vibration_device.h" | ||
| 30 | 35 | ||
| 31 | namespace Service::HID { | 36 | namespace Service::HID { |
| 32 | 37 | ||
| @@ -52,6 +57,7 @@ void ResourceManager::Initialize() { | |||
| 52 | 57 | ||
| 53 | system.HIDCore().ReloadInputDevices(); | 58 | system.HIDCore().ReloadInputDevices(); |
| 54 | 59 | ||
| 60 | handheld_config = std::make_shared<HandheldConfig>(); | ||
| 55 | InitializeHidCommonSampler(); | 61 | InitializeHidCommonSampler(); |
| 56 | InitializeTouchScreenSampler(); | 62 | InitializeTouchScreenSampler(); |
| 57 | InitializeConsoleSixAxisSampler(); | 63 | InitializeConsoleSixAxisSampler(); |
| @@ -174,7 +180,7 @@ void ResourceManager::InitializeHidCommonSampler() { | |||
| 174 | debug_pad->SetAppletResource(applet_resource, &shared_mutex); | 180 | debug_pad->SetAppletResource(applet_resource, &shared_mutex); |
| 175 | digitizer->SetAppletResource(applet_resource, &shared_mutex); | 181 | digitizer->SetAppletResource(applet_resource, &shared_mutex); |
| 176 | keyboard->SetAppletResource(applet_resource, &shared_mutex); | 182 | keyboard->SetAppletResource(applet_resource, &shared_mutex); |
| 177 | npad->SetNpadExternals(applet_resource, &shared_mutex); | 183 | npad->SetNpadExternals(applet_resource, &shared_mutex, handheld_config); |
| 178 | six_axis->SetAppletResource(applet_resource, &shared_mutex); | 184 | six_axis->SetAppletResource(applet_resource, &shared_mutex); |
| 179 | mouse->SetAppletResource(applet_resource, &shared_mutex); | 185 | mouse->SetAppletResource(applet_resource, &shared_mutex); |
| 180 | debug_mouse->SetAppletResource(applet_resource, &shared_mutex); | 186 | debug_mouse->SetAppletResource(applet_resource, &shared_mutex); |
| @@ -257,6 +263,121 @@ void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) { | |||
| 257 | applet_resource->EnableTouchScreen(aruid, is_enabled); | 263 | applet_resource->EnableTouchScreen(aruid, is_enabled); |
| 258 | } | 264 | } |
| 259 | 265 | ||
| 266 | NpadVibrationBase* ResourceManager::GetVibrationDevice( | ||
| 267 | const Core::HID::VibrationDeviceHandle& handle) { | ||
| 268 | return npad->GetVibrationDevice(handle); | ||
| 269 | } | ||
| 270 | |||
| 271 | NpadN64VibrationDevice* ResourceManager::GetN64VibrationDevice( | ||
| 272 | const Core::HID::VibrationDeviceHandle& handle) { | ||
| 273 | return npad->GetN64VibrationDevice(handle); | ||
| 274 | } | ||
| 275 | |||
| 276 | NpadVibrationDevice* ResourceManager::GetNSVibrationDevice( | ||
| 277 | const Core::HID::VibrationDeviceHandle& handle) { | ||
| 278 | return npad->GetNSVibrationDevice(handle); | ||
| 279 | } | ||
| 280 | |||
| 281 | NpadGcVibrationDevice* ResourceManager::GetGcVibrationDevice( | ||
| 282 | const Core::HID::VibrationDeviceHandle& handle) { | ||
| 283 | return npad->GetGcVibrationDevice(handle); | ||
| 284 | } | ||
| 285 | |||
| 286 | Result ResourceManager::SetAruidValidForVibration(u64 aruid, bool is_enabled) { | ||
| 287 | std::scoped_lock lock{shared_mutex}; | ||
| 288 | const bool has_changed = applet_resource->SetAruidValidForVibration(aruid, is_enabled); | ||
| 289 | |||
| 290 | if (has_changed) { | ||
| 291 | auto devices = npad->GetAllVibrationDevices(); | ||
| 292 | for ([[maybe_unused]] auto* device : devices) { | ||
| 293 | // TODO | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | auto* vibration_handler = npad->GetVibrationHandler(); | ||
| 298 | if (aruid != vibration_handler->GetSessionAruid()) { | ||
| 299 | vibration_handler->EndPermitVibrationSession(); | ||
| 300 | } | ||
| 301 | |||
| 302 | return ResultSuccess; | ||
| 303 | } | ||
| 304 | |||
| 305 | void ResourceManager::SetForceHandheldStyleVibration(bool is_forced) { | ||
| 306 | handheld_config->is_force_handheld_style_vibration = is_forced; | ||
| 307 | } | ||
| 308 | |||
| 309 | Result ResourceManager::IsVibrationAruidActive(u64 aruid, bool& is_active) const { | ||
| 310 | std::scoped_lock lock{shared_mutex}; | ||
| 311 | is_active = applet_resource->IsVibrationAruidActive(aruid); | ||
| 312 | return ResultSuccess; | ||
| 313 | } | ||
| 314 | |||
| 315 | Result ResourceManager::GetVibrationDeviceInfo(Core::HID::VibrationDeviceInfo& device_info, | ||
| 316 | const Core::HID::VibrationDeviceHandle& handle) { | ||
| 317 | bool check_device_index = false; | ||
| 318 | |||
| 319 | const Result is_valid = IsVibrationHandleValid(handle); | ||
| 320 | if (is_valid.IsError()) { | ||
| 321 | return is_valid; | ||
| 322 | } | ||
| 323 | |||
| 324 | switch (handle.npad_type) { | ||
| 325 | case Core::HID::NpadStyleIndex::Fullkey: | ||
| 326 | case Core::HID::NpadStyleIndex::Handheld: | ||
| 327 | case Core::HID::NpadStyleIndex::JoyconDual: | ||
| 328 | case Core::HID::NpadStyleIndex::JoyconLeft: | ||
| 329 | case Core::HID::NpadStyleIndex::JoyconRight: | ||
| 330 | device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; | ||
| 331 | check_device_index = true; | ||
| 332 | break; | ||
| 333 | case Core::HID::NpadStyleIndex::GameCube: | ||
| 334 | device_info.type = Core::HID::VibrationDeviceType::GcErm; | ||
| 335 | break; | ||
| 336 | case Core::HID::NpadStyleIndex::N64: | ||
| 337 | device_info.type = Core::HID::VibrationDeviceType::N64; | ||
| 338 | break; | ||
| 339 | default: | ||
| 340 | device_info.type = Core::HID::VibrationDeviceType::Unknown; | ||
| 341 | break; | ||
| 342 | } | ||
| 343 | |||
| 344 | device_info.position = Core::HID::VibrationDevicePosition::None; | ||
| 345 | if (check_device_index) { | ||
| 346 | switch (handle.device_index) { | ||
| 347 | case Core::HID::DeviceIndex::Left: | ||
| 348 | device_info.position = Core::HID::VibrationDevicePosition::Left; | ||
| 349 | break; | ||
| 350 | case Core::HID::DeviceIndex::Right: | ||
| 351 | device_info.position = Core::HID::VibrationDevicePosition::Right; | ||
| 352 | break; | ||
| 353 | case Core::HID::DeviceIndex::None: | ||
| 354 | default: | ||
| 355 | ASSERT_MSG(false, "DeviceIndex should never be None!"); | ||
| 356 | break; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | return ResultSuccess; | ||
| 360 | } | ||
| 361 | |||
| 362 | Result ResourceManager::SendVibrationValue(u64 aruid, | ||
| 363 | const Core::HID::VibrationDeviceHandle& handle, | ||
| 364 | const Core::HID::VibrationValue& value) { | ||
| 365 | bool has_active_aruid{}; | ||
| 366 | NpadVibrationDevice* device{nullptr}; | ||
| 367 | Result result = IsVibrationAruidActive(aruid, has_active_aruid); | ||
| 368 | |||
| 369 | if (result.IsSuccess() && has_active_aruid) { | ||
| 370 | result = IsVibrationHandleValid(handle); | ||
| 371 | } | ||
| 372 | if (result.IsSuccess() && has_active_aruid) { | ||
| 373 | device = GetNSVibrationDevice(handle); | ||
| 374 | } | ||
| 375 | if (device != nullptr) { | ||
| 376 | result = device->SendVibrationValue(value); | ||
| 377 | } | ||
| 378 | return result; | ||
| 379 | } | ||
| 380 | |||
| 260 | void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) { | 381 | void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) { |
| 261 | auto& core_timing = system.CoreTiming(); | 382 | auto& core_timing = system.CoreTiming(); |
| 262 | debug_pad->OnUpdate(core_timing); | 383 | debug_pad->OnUpdate(core_timing); |
diff --git a/src/hid_core/resource_manager.h b/src/hid_core/resource_manager.h index 7a21d8eb8..128e00125 100644 --- a/src/hid_core/resource_manager.h +++ b/src/hid_core/resource_manager.h | |||
| @@ -10,6 +10,12 @@ namespace Core { | |||
| 10 | class System; | 10 | class System; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | namespace Core::HID { | ||
| 14 | struct VibrationDeviceHandle; | ||
| 15 | struct VibrationValue; | ||
| 16 | struct VibrationDeviceInfo; | ||
| 17 | } // namespace Core::HID | ||
| 18 | |||
| 13 | namespace Core::Timing { | 19 | namespace Core::Timing { |
| 14 | struct EventType; | 20 | struct EventType; |
| 15 | } | 21 | } |
| @@ -37,6 +43,11 @@ class SixAxis; | |||
| 37 | class SleepButton; | 43 | class SleepButton; |
| 38 | class TouchScreen; | 44 | class TouchScreen; |
| 39 | class UniquePad; | 45 | class UniquePad; |
| 46 | class NpadVibrationBase; | ||
| 47 | class NpadN64VibrationDevice; | ||
| 48 | class NpadGcVibrationDevice; | ||
| 49 | class NpadVibrationDevice; | ||
| 50 | struct HandheldConfig; | ||
| 40 | 51 | ||
| 41 | class ResourceManager { | 52 | class ResourceManager { |
| 42 | 53 | ||
| @@ -79,6 +90,18 @@ public: | |||
| 79 | void EnablePadInput(u64 aruid, bool is_enabled); | 90 | void EnablePadInput(u64 aruid, bool is_enabled); |
| 80 | void EnableTouchScreen(u64 aruid, bool is_enabled); | 91 | void EnableTouchScreen(u64 aruid, bool is_enabled); |
| 81 | 92 | ||
| 93 | NpadVibrationBase* GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle); | ||
| 94 | NpadN64VibrationDevice* GetN64VibrationDevice(const Core::HID::VibrationDeviceHandle& handle); | ||
| 95 | NpadVibrationDevice* GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle); | ||
| 96 | NpadGcVibrationDevice* GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle); | ||
| 97 | Result SetAruidValidForVibration(u64 aruid, bool is_enabled); | ||
| 98 | void SetForceHandheldStyleVibration(bool is_forced); | ||
| 99 | Result IsVibrationAruidActive(u64 aruid, bool& is_active) const; | ||
| 100 | Result GetVibrationDeviceInfo(Core::HID::VibrationDeviceInfo& device_info, | ||
| 101 | const Core::HID::VibrationDeviceHandle& handle); | ||
| 102 | Result SendVibrationValue(u64 aruid, const Core::HID::VibrationDeviceHandle& handle, | ||
| 103 | const Core::HID::VibrationValue& value); | ||
| 104 | |||
| 82 | void UpdateControllers(std::chrono::nanoseconds ns_late); | 105 | void UpdateControllers(std::chrono::nanoseconds ns_late); |
| 83 | void UpdateNpad(std::chrono::nanoseconds ns_late); | 106 | void UpdateNpad(std::chrono::nanoseconds ns_late); |
| 84 | void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late); | 107 | void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late); |
| @@ -113,6 +136,8 @@ private: | |||
| 113 | std::shared_ptr<TouchScreen> touch_screen = nullptr; | 136 | std::shared_ptr<TouchScreen> touch_screen = nullptr; |
| 114 | std::shared_ptr<UniquePad> unique_pad = nullptr; | 137 | std::shared_ptr<UniquePad> unique_pad = nullptr; |
| 115 | 138 | ||
| 139 | std::shared_ptr<HandheldConfig> handheld_config = nullptr; | ||
| 140 | |||
| 116 | // TODO: Create these resources | 141 | // TODO: Create these resources |
| 117 | // std::shared_ptr<AudioControl> audio_control = nullptr; | 142 | // std::shared_ptr<AudioControl> audio_control = nullptr; |
| 118 | // std::shared_ptr<ButtonConfig> button_config = nullptr; | 143 | // std::shared_ptr<ButtonConfig> button_config = nullptr; |
diff --git a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp index d4e4181bf..e399edfd7 100644 --- a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp +++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp | |||
| @@ -115,7 +115,7 @@ Result NpadAbstractIrSensorHandler::GetXcdHandleForNpadWithIrSensor(u64& handle) | |||
| 115 | if (sensor_state < NpadIrSensorState::Available) { | 115 | if (sensor_state < NpadIrSensorState::Available) { |
| 116 | return ResultIrSensorIsNotReady; | 116 | return ResultIrSensorIsNotReady; |
| 117 | } | 117 | } |
| 118 | handle = xcd_handle; | 118 | // handle = xcd_handle; |
| 119 | return ResultSuccess; | 119 | return ResultSuccess; |
| 120 | } | 120 | } |
| 121 | 121 | ||
diff --git a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h index fe8e005af..997811511 100644 --- a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h +++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | #include "core/hle/result.h" | 7 | #include "core/hle/result.h" |
| 8 | #include "hid_core/hid_types.h" | 8 | #include "hid_core/hid_types.h" |
| 9 | 9 | ||
| 10 | namespace Core::HID { | ||
| 11 | class EmulatedController; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace Kernel { | 14 | namespace Kernel { |
| 11 | class KEvent; | 15 | class KEvent; |
| 12 | class KReadableEvent; | 16 | class KReadableEvent; |
| @@ -50,7 +54,7 @@ private: | |||
| 50 | 54 | ||
| 51 | s32 ref_counter{}; | 55 | s32 ref_counter{}; |
| 52 | Kernel::KEvent* ir_sensor_event{nullptr}; | 56 | Kernel::KEvent* ir_sensor_event{nullptr}; |
| 53 | u64 xcd_handle{}; | 57 | Core::HID::EmulatedController* xcd_handle{}; |
| 54 | NpadIrSensorState sensor_state{}; | 58 | NpadIrSensorState sensor_state{}; |
| 55 | }; | 59 | }; |
| 56 | } // namespace Service::HID | 60 | } // namespace Service::HID |
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp index 2c7691d7c..435b095f0 100644 --- a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp +++ b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include "hid_core/hid_core.h" | ||
| 4 | #include "hid_core/hid_result.h" | 5 | #include "hid_core/hid_result.h" |
| 5 | #include "hid_core/resources/abstracted_pad/abstract_pad.h" | 6 | #include "hid_core/resources/abstracted_pad/abstract_pad.h" |
| 6 | #include "hid_core/resources/applet_resource.h" | 7 | #include "hid_core/resources/applet_resource.h" |
| @@ -16,7 +17,7 @@ void AbstractPad::SetExternals(AppletResourceHolder* applet_resource, | |||
| 16 | CaptureButtonResource* capture_button_resource, | 17 | CaptureButtonResource* capture_button_resource, |
| 17 | HomeButtonResource* home_button_resource, | 18 | HomeButtonResource* home_button_resource, |
| 18 | SixAxisResource* sixaxis_resource, PalmaResource* palma_resource, | 19 | SixAxisResource* sixaxis_resource, PalmaResource* palma_resource, |
| 19 | VibrationHandler* vibration) { | 20 | NpadVibration* vibration, Core::HID::HIDCore* core) { |
| 20 | applet_resource_holder = applet_resource; | 21 | applet_resource_holder = applet_resource; |
| 21 | 22 | ||
| 22 | properties_handler.SetAppletResource(applet_resource_holder); | 23 | properties_handler.SetAppletResource(applet_resource_holder); |
| @@ -35,13 +36,14 @@ void AbstractPad::SetExternals(AppletResourceHolder* applet_resource, | |||
| 35 | mcu_handler.SetAbstractPadHolder(&abstract_pad_holder); | 36 | mcu_handler.SetAbstractPadHolder(&abstract_pad_holder); |
| 36 | mcu_handler.SetPropertiesHandler(&properties_handler); | 37 | mcu_handler.SetPropertiesHandler(&properties_handler); |
| 37 | 38 | ||
| 38 | std::array<NpadVibrationDevice*, 2> vibration_devices{&vibration_left, &vibration_right}; | ||
| 39 | vibration_handler.SetAppletResource(applet_resource_holder); | 39 | vibration_handler.SetAppletResource(applet_resource_holder); |
| 40 | vibration_handler.SetAbstractPadHolder(&abstract_pad_holder); | 40 | vibration_handler.SetAbstractPadHolder(&abstract_pad_holder); |
| 41 | vibration_handler.SetPropertiesHandler(&properties_handler); | 41 | vibration_handler.SetPropertiesHandler(&properties_handler); |
| 42 | vibration_handler.SetN64Vibration(&vibration_n64); | 42 | vibration_handler.SetN64Vibration(&vibration_n64); |
| 43 | vibration_handler.SetVibration(vibration_devices); | 43 | vibration_handler.SetVibration(&vibration_left, &vibration_right); |
| 44 | vibration_handler.SetGcVibration(&vibration_gc); | 44 | vibration_handler.SetGcVibration(&vibration_gc); |
| 45 | vibration_handler.SetVibrationHandler(vibration); | ||
| 46 | vibration_handler.SetHidCore(core); | ||
| 45 | 47 | ||
| 46 | sixaxis_handler.SetAppletResource(applet_resource_holder); | 48 | sixaxis_handler.SetAppletResource(applet_resource_holder); |
| 47 | sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder); | 49 | sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder); |
| @@ -239,11 +241,6 @@ NpadVibrationDevice* AbstractPad::GetVibrationDevice(Core::HID::DeviceIndex devi | |||
| 239 | return &vibration_left; | 241 | return &vibration_left; |
| 240 | } | 242 | } |
| 241 | 243 | ||
| 242 | void AbstractPad::GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list) { | ||
| 243 | list.emplace_back(&vibration_left); | ||
| 244 | list.emplace_back(&vibration_right); | ||
| 245 | } | ||
| 246 | |||
| 247 | NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() { | 244 | NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() { |
| 248 | return &vibration_gc; | 245 | return &vibration_gc; |
| 249 | } | 246 | } |
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.h b/src/hid_core/resources/abstracted_pad/abstract_pad.h index cbdf84af7..329792457 100644 --- a/src/hid_core/resources/abstracted_pad/abstract_pad.h +++ b/src/hid_core/resources/abstracted_pad/abstract_pad.h | |||
| @@ -32,7 +32,6 @@ class AppletResource; | |||
| 32 | class SixAxisResource; | 32 | class SixAxisResource; |
| 33 | class PalmaResource; | 33 | class PalmaResource; |
| 34 | class NPadResource; | 34 | class NPadResource; |
| 35 | class AbstractPad; | ||
| 36 | class NpadLastActiveHandler; | 35 | class NpadLastActiveHandler; |
| 37 | class NpadIrNfcHandler; | 36 | class NpadIrNfcHandler; |
| 38 | class UniquePads; | 37 | class UniquePads; |
| @@ -44,7 +43,6 @@ class NpadGcVibration; | |||
| 44 | 43 | ||
| 45 | class CaptureButtonResource; | 44 | class CaptureButtonResource; |
| 46 | class HomeButtonResource; | 45 | class HomeButtonResource; |
| 47 | class VibrationHandler; | ||
| 48 | 46 | ||
| 49 | struct HandheldConfig; | 47 | struct HandheldConfig; |
| 50 | 48 | ||
| @@ -57,7 +55,8 @@ public: | |||
| 57 | void SetExternals(AppletResourceHolder* applet_resource, | 55 | void SetExternals(AppletResourceHolder* applet_resource, |
| 58 | CaptureButtonResource* capture_button_resource, | 56 | CaptureButtonResource* capture_button_resource, |
| 59 | HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource, | 57 | HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource, |
| 60 | PalmaResource* palma_resource, VibrationHandler* vibration); | 58 | PalmaResource* palma_resource, NpadVibration* vibration, |
| 59 | Core::HID::HIDCore* core); | ||
| 61 | void SetNpadId(Core::HID::NpadIdType npad_id); | 60 | void SetNpadId(Core::HID::NpadIdType npad_id); |
| 62 | 61 | ||
| 63 | Result Activate(); | 62 | Result Activate(); |
| @@ -78,7 +77,6 @@ public: | |||
| 78 | 77 | ||
| 79 | NpadN64VibrationDevice* GetN64VibrationDevice(); | 78 | NpadN64VibrationDevice* GetN64VibrationDevice(); |
| 80 | NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index); | 79 | NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index); |
| 81 | void GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list); | ||
| 82 | NpadGcVibrationDevice* GetGCVibrationDevice(); | 80 | NpadGcVibrationDevice* GetGCVibrationDevice(); |
| 83 | 81 | ||
| 84 | Core::HID::NpadIdType GetLastActiveNpad(); | 82 | Core::HID::NpadIdType GetLastActiveNpad(); |
diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp index a00d6c9de..ca64b0a43 100644 --- a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp +++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include "hid_core/frontend/emulated_controller.h" | ||
| 5 | #include "hid_core/hid_core.h" | ||
| 4 | #include "hid_core/hid_result.h" | 6 | #include "hid_core/hid_result.h" |
| 5 | #include "hid_core/hid_util.h" | 7 | #include "hid_core/hid_util.h" |
| 6 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" | 8 | #include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" |
| @@ -30,14 +32,22 @@ void NpadAbstractVibrationHandler::SetPropertiesHandler(NpadAbstractPropertiesHa | |||
| 30 | properties_handler = handler; | 32 | properties_handler = handler; |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 35 | void NpadAbstractVibrationHandler::SetVibrationHandler(NpadVibration* handler) { | ||
| 36 | vibration_handler = handler; | ||
| 37 | } | ||
| 38 | |||
| 39 | void NpadAbstractVibrationHandler::SetHidCore(Core::HID::HIDCore* core) { | ||
| 40 | hid_core = core; | ||
| 41 | } | ||
| 42 | |||
| 33 | void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) { | 43 | void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) { |
| 34 | n64_vibration_device = n64_device; | 44 | n64_vibration_device = n64_device; |
| 35 | } | 45 | } |
| 36 | 46 | ||
| 37 | void NpadAbstractVibrationHandler::SetVibration(std::span<NpadVibrationDevice*> device) { | 47 | void NpadAbstractVibrationHandler::SetVibration(NpadVibrationDevice* left_device, |
| 38 | for (std::size_t i = 0; i < device.size() && i < vibration_device.size(); i++) { | 48 | NpadVibrationDevice* right_device) { |
| 39 | vibration_device[i] = device[i]; | 49 | left_vibration_device = left_device; |
| 40 | } | 50 | right_vibration_device = right_device; |
| 41 | } | 51 | } |
| 42 | 52 | ||
| 43 | void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) { | 53 | void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) { |
| @@ -69,5 +79,29 @@ void NpadAbstractVibrationHandler::UpdateVibrationState() { | |||
| 69 | if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) { | 79 | if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) { |
| 70 | // TODO | 80 | // TODO |
| 71 | } | 81 | } |
| 82 | |||
| 83 | // TODO: This function isn't accurate. It's supposed to get 5 abstracted pads from the | ||
| 84 | // NpadAbstractPropertiesHandler but this handler isn't fully implemented yet | ||
| 85 | IAbstractedPad abstracted_pad{}; | ||
| 86 | const auto npad_id = properties_handler->GetNpadId(); | ||
| 87 | abstracted_pad.xcd_handle = hid_core->GetEmulatedController(npad_id); | ||
| 88 | abstracted_pad.internal_flags.is_connected.Assign(abstracted_pad.xcd_handle->IsConnected()); | ||
| 89 | |||
| 90 | if (abstracted_pad.internal_flags.is_connected) { | ||
| 91 | left_vibration_device->Mount(abstracted_pad, Core::HID::DeviceIndex::Left, | ||
| 92 | vibration_handler); | ||
| 93 | right_vibration_device->Mount(abstracted_pad, Core::HID::DeviceIndex::Right, | ||
| 94 | vibration_handler); | ||
| 95 | gc_vibration_device->Mount(abstracted_pad, 0, vibration_handler); | ||
| 96 | gc_vibration_device->Mount(abstracted_pad, 0, vibration_handler); | ||
| 97 | n64_vibration_device->Mount(abstracted_pad, vibration_handler); | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | |||
| 101 | left_vibration_device->Unmount(); | ||
| 102 | right_vibration_device->Unmount(); | ||
| 103 | gc_vibration_device->Unmount(); | ||
| 104 | gc_vibration_device->Unmount(); | ||
| 105 | n64_vibration_device->Unmount(); | ||
| 72 | } | 106 | } |
| 73 | } // namespace Service::HID | 107 | } // namespace Service::HID |
diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h index aeb07ce86..8bc8129c2 100644 --- a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h +++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h | |||
| @@ -9,6 +9,10 @@ | |||
| 9 | #include "core/hle/result.h" | 9 | #include "core/hle/result.h" |
| 10 | #include "hid_core/hid_types.h" | 10 | #include "hid_core/hid_types.h" |
| 11 | 11 | ||
| 12 | namespace Core::HID { | ||
| 13 | class HIDCore; | ||
| 14 | } | ||
| 15 | |||
| 12 | namespace Service::HID { | 16 | namespace Service::HID { |
| 13 | struct AppletResourceHolder; | 17 | struct AppletResourceHolder; |
| 14 | class NpadAbstractedPadHolder; | 18 | class NpadAbstractedPadHolder; |
| @@ -27,9 +31,11 @@ public: | |||
| 27 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); | 31 | void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); |
| 28 | void SetAppletResource(AppletResourceHolder* applet_resource); | 32 | void SetAppletResource(AppletResourceHolder* applet_resource); |
| 29 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); | 33 | void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); |
| 34 | void SetVibrationHandler(NpadVibration* handler); | ||
| 35 | void SetHidCore(Core::HID::HIDCore* core); | ||
| 30 | 36 | ||
| 31 | void SetN64Vibration(NpadN64VibrationDevice* n64_device); | 37 | void SetN64Vibration(NpadN64VibrationDevice* n64_device); |
| 32 | void SetVibration(std::span<NpadVibrationDevice*> device); | 38 | void SetVibration(NpadVibrationDevice* left_device, NpadVibrationDevice* right_device); |
| 33 | void SetGcVibration(NpadGcVibrationDevice* gc_device); | 39 | void SetGcVibration(NpadGcVibrationDevice* gc_device); |
| 34 | 40 | ||
| 35 | Result IncrementRefCounter(); | 41 | Result IncrementRefCounter(); |
| @@ -41,9 +47,11 @@ private: | |||
| 41 | AppletResourceHolder* applet_resource_holder{nullptr}; | 47 | AppletResourceHolder* applet_resource_holder{nullptr}; |
| 42 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; | 48 | NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; |
| 43 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; | 49 | NpadAbstractPropertiesHandler* properties_handler{nullptr}; |
| 50 | Core::HID::HIDCore* hid_core{nullptr}; | ||
| 44 | 51 | ||
| 45 | NpadN64VibrationDevice* n64_vibration_device{nullptr}; | 52 | NpadN64VibrationDevice* n64_vibration_device{nullptr}; |
| 46 | std::array<NpadVibrationDevice*, 2> vibration_device{}; | 53 | NpadVibrationDevice* left_vibration_device{}; |
| 54 | NpadVibrationDevice* right_vibration_device{}; | ||
| 47 | NpadGcVibrationDevice* gc_vibration_device{nullptr}; | 55 | NpadGcVibrationDevice* gc_vibration_device{nullptr}; |
| 48 | NpadVibration* vibration_handler{nullptr}; | 56 | NpadVibration* vibration_handler{nullptr}; |
| 49 | s32 ref_counter{}; | 57 | s32 ref_counter{}; |
diff --git a/src/hid_core/resources/applet_resource.cpp b/src/hid_core/resources/applet_resource.cpp index a84826050..db4134037 100644 --- a/src/hid_core/resources/applet_resource.cpp +++ b/src/hid_core/resources/applet_resource.cpp | |||
| @@ -200,6 +200,25 @@ void AppletResource::EnableInput(u64 aruid, bool is_enabled) { | |||
| 200 | data[index].flag.enable_touchscreen.Assign(is_enabled); | 200 | data[index].flag.enable_touchscreen.Assign(is_enabled); |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | bool AppletResource::SetAruidValidForVibration(u64 aruid, bool is_enabled) { | ||
| 204 | const u64 index = GetIndexFromAruid(aruid); | ||
| 205 | if (index >= AruidIndexMax) { | ||
| 206 | return false; | ||
| 207 | } | ||
| 208 | |||
| 209 | if (!is_enabled && aruid == active_vibration_aruid) { | ||
| 210 | active_vibration_aruid = SystemAruid; | ||
| 211 | return true; | ||
| 212 | } | ||
| 213 | |||
| 214 | if (is_enabled && aruid != active_vibration_aruid) { | ||
| 215 | active_vibration_aruid = aruid; | ||
| 216 | return true; | ||
| 217 | } | ||
| 218 | |||
| 219 | return false; | ||
| 220 | } | ||
| 221 | |||
| 203 | void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) { | 222 | void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) { |
| 204 | const u64 index = GetIndexFromAruid(aruid); | 223 | const u64 index = GetIndexFromAruid(aruid); |
| 205 | if (index >= AruidIndexMax) { | 224 | if (index >= AruidIndexMax) { |
diff --git a/src/hid_core/resources/applet_resource.h b/src/hid_core/resources/applet_resource.h index f3f32bac1..e9710d306 100644 --- a/src/hid_core/resources/applet_resource.h +++ b/src/hid_core/resources/applet_resource.h | |||
| @@ -101,6 +101,7 @@ public: | |||
| 101 | Result DestroySevenSixAxisTransferMemory(); | 101 | Result DestroySevenSixAxisTransferMemory(); |
| 102 | 102 | ||
| 103 | void EnableInput(u64 aruid, bool is_enabled); | 103 | void EnableInput(u64 aruid, bool is_enabled); |
| 104 | bool SetAruidValidForVibration(u64 aruid, bool is_enabled); | ||
| 104 | void EnableSixAxisSensor(u64 aruid, bool is_enabled); | 105 | void EnableSixAxisSensor(u64 aruid, bool is_enabled); |
| 105 | void EnablePadInput(u64 aruid, bool is_enabled); | 106 | void EnablePadInput(u64 aruid, bool is_enabled); |
| 106 | void EnableTouchScreen(u64 aruid, bool is_enabled); | 107 | void EnableTouchScreen(u64 aruid, bool is_enabled); |
diff --git a/src/hid_core/resources/hid_firmware_settings.cpp b/src/hid_core/resources/hid_firmware_settings.cpp index 9fa0db17e..00ceff7e6 100644 --- a/src/hid_core/resources/hid_firmware_settings.cpp +++ b/src/hid_core/resources/hid_firmware_settings.cpp | |||
| @@ -1,11 +1,14 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include "core/hle/service/set/system_settings_server.h" | ||
| 5 | #include "core/hle/service/sm/sm.h" | ||
| 4 | #include "hid_core/resources/hid_firmware_settings.h" | 6 | #include "hid_core/resources/hid_firmware_settings.h" |
| 5 | 7 | ||
| 6 | namespace Service::HID { | 8 | namespace Service::HID { |
| 7 | 9 | ||
| 8 | HidFirmwareSettings::HidFirmwareSettings() { | 10 | HidFirmwareSettings::HidFirmwareSettings(Core::System& system) { |
| 11 | m_set_sys = system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys"); | ||
| 9 | LoadSettings(true); | 12 | LoadSettings(true); |
| 10 | } | 13 | } |
| 11 | 14 | ||
| @@ -18,21 +21,25 @@ void HidFirmwareSettings::LoadSettings(bool reload_config) { | |||
| 18 | return; | 21 | return; |
| 19 | } | 22 | } |
| 20 | 23 | ||
| 21 | // TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values | 24 | m_set_sys->GetSettingsItemValue<bool>(is_debug_pad_enabled, "hid_debug", "enables_debugpad"); |
| 22 | 25 | m_set_sys->GetSettingsItemValue<bool>(is_device_managed, "hid_debug", "manages_devices"); | |
| 23 | is_debug_pad_enabled = true; | 26 | m_set_sys->GetSettingsItemValue<bool>(is_touch_i2c_managed, "hid_debug", |
| 24 | is_device_managed = true; | 27 | "manages_touch_ic_i2c"); |
| 25 | is_touch_i2c_managed = is_device_managed; | 28 | m_set_sys->GetSettingsItemValue<bool>(is_future_devices_emulated, "hid_debug", |
| 26 | is_future_devices_emulated = false; | 29 | "emulate_future_device"); |
| 27 | is_mcu_hardware_error_emulated = false; | 30 | m_set_sys->GetSettingsItemValue<bool>(is_mcu_hardware_error_emulated, "hid_debug", |
| 28 | is_rail_enabled = true; | 31 | "emulate_mcu_hardware_error"); |
| 29 | is_firmware_update_failure_emulated = false; | 32 | m_set_sys->GetSettingsItemValue<bool>(is_rail_enabled, "hid_debug", "enables_rail"); |
| 33 | m_set_sys->GetSettingsItemValue<bool>(is_firmware_update_failure_emulated, "hid_debug", | ||
| 34 | "emulate_firmware_update_failure"); | ||
| 30 | is_firmware_update_failure = {}; | 35 | is_firmware_update_failure = {}; |
| 31 | is_ble_disabled = false; | 36 | m_set_sys->GetSettingsItemValue<bool>(is_ble_disabled, "hid_debug", "ble_disabled"); |
| 32 | is_dscale_disabled = false; | 37 | m_set_sys->GetSettingsItemValue<bool>(is_dscale_disabled, "hid_debug", "dscale_disabled"); |
| 33 | is_handheld_forced = true; | 38 | m_set_sys->GetSettingsItemValue<bool>(is_handheld_forced, "hid_debug", "force_handheld"); |
| 34 | features_per_id_disabled = {}; | 39 | features_per_id_disabled = {}; |
| 35 | is_touch_firmware_auto_update_disabled = false; | 40 | m_set_sys->GetSettingsItemValue<bool>(is_touch_firmware_auto_update_disabled, "hid_debug", |
| 41 | "touch_firmware_auto_update_disabled"); | ||
| 42 | |||
| 36 | is_initialized = true; | 43 | is_initialized = true; |
| 37 | } | 44 | } |
| 38 | 45 | ||
diff --git a/src/hid_core/resources/hid_firmware_settings.h b/src/hid_core/resources/hid_firmware_settings.h index 00201fd94..3694fa9a3 100644 --- a/src/hid_core/resources/hid_firmware_settings.h +++ b/src/hid_core/resources/hid_firmware_settings.h | |||
| @@ -5,6 +5,14 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | 7 | ||
| 8 | namespace Core { | ||
| 9 | class System; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Service::Set { | ||
| 13 | class ISystemSettingsServer; | ||
| 14 | } | ||
| 15 | |||
| 8 | namespace Service::HID { | 16 | namespace Service::HID { |
| 9 | 17 | ||
| 10 | /// Loads firmware config from nn::settings::fwdbg | 18 | /// Loads firmware config from nn::settings::fwdbg |
| @@ -13,7 +21,7 @@ public: | |||
| 13 | using FirmwareSetting = std::array<u8, 4>; | 21 | using FirmwareSetting = std::array<u8, 4>; |
| 14 | using FeaturesPerId = std::array<bool, 0xA8>; | 22 | using FeaturesPerId = std::array<bool, 0xA8>; |
| 15 | 23 | ||
| 16 | HidFirmwareSettings(); | 24 | HidFirmwareSettings(Core::System& system); |
| 17 | 25 | ||
| 18 | void Reload(); | 26 | void Reload(); |
| 19 | void LoadSettings(bool reload_config); | 27 | void LoadSettings(bool reload_config); |
| @@ -49,6 +57,8 @@ private: | |||
| 49 | bool is_touch_firmware_auto_update_disabled{}; | 57 | bool is_touch_firmware_auto_update_disabled{}; |
| 50 | FirmwareSetting is_firmware_update_failure{}; | 58 | FirmwareSetting is_firmware_update_failure{}; |
| 51 | FeaturesPerId features_per_id_disabled{}; | 59 | FeaturesPerId features_per_id_disabled{}; |
| 60 | |||
| 61 | std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; | ||
| 52 | }; | 62 | }; |
| 53 | 63 | ||
| 54 | } // namespace Service::HID | 64 | } // namespace Service::HID |
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index 97537a2e2..212f01429 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include "hid_core/hid_util.h" | 21 | #include "hid_core/hid_util.h" |
| 22 | #include "hid_core/resources/applet_resource.h" | 22 | #include "hid_core/resources/applet_resource.h" |
| 23 | #include "hid_core/resources/npad/npad.h" | 23 | #include "hid_core/resources/npad/npad.h" |
| 24 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 24 | #include "hid_core/resources/shared_memory_format.h" | 25 | #include "hid_core/resources/shared_memory_format.h" |
| 25 | 26 | ||
| 26 | namespace Service::HID { | 27 | namespace Service::HID { |
| @@ -31,10 +32,6 @@ NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service | |||
| 31 | for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) { | 32 | for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) { |
| 32 | auto& controller = controller_data[aruid_index][i]; | 33 | auto& controller = controller_data[aruid_index][i]; |
| 33 | controller.device = hid_core.GetEmulatedControllerByIndex(i); | 34 | controller.device = hid_core.GetEmulatedControllerByIndex(i); |
| 34 | controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = | ||
| 35 | Core::HID::DEFAULT_VIBRATION_VALUE; | ||
| 36 | controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex] | ||
| 37 | .latest_vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE; | ||
| 38 | Core::HID::ControllerUpdateCallback engine_callback{ | 35 | Core::HID::ControllerUpdateCallback engine_callback{ |
| 39 | .on_change = | 36 | .on_change = |
| 40 | [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, | 37 | [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, |
| @@ -43,6 +40,10 @@ NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service | |||
| 43 | controller.callback_key = controller.device->SetCallback(engine_callback); | 40 | controller.callback_key = controller.device->SetCallback(engine_callback); |
| 44 | } | 41 | } |
| 45 | } | 42 | } |
| 43 | for (std::size_t i = 0; i < abstracted_pads.size(); ++i) { | ||
| 44 | abstracted_pads[i] = AbstractPad{}; | ||
| 45 | abstracted_pads[i].SetNpadId(IndexToNpadIdType(i)); | ||
| 46 | } | ||
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | NPad::~NPad() { | 49 | NPad::~NPad() { |
| @@ -359,6 +360,7 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) { | |||
| 359 | npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id); | 360 | npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id); |
| 360 | WriteEmptyEntry(controller.shared_memory); | 361 | WriteEmptyEntry(controller.shared_memory); |
| 361 | hid_core.SetLastActiveController(npad_id); | 362 | hid_core.SetLastActiveController(npad_id); |
| 363 | abstracted_pads[NpadIdTypeToIndex(npad_id)].Update(); | ||
| 362 | } | 364 | } |
| 363 | 365 | ||
| 364 | void NPad::WriteEmptyEntry(NpadInternalState* npad) { | 366 | void NPad::WriteEmptyEntry(NpadInternalState* npad) { |
| @@ -740,171 +742,6 @@ bool NPad::SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID: | |||
| 740 | return true; | 742 | return true; |
| 741 | } | 743 | } |
| 742 | 744 | ||
| 743 | bool NPad::VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id, | ||
| 744 | std::size_t device_index, | ||
| 745 | const Core::HID::VibrationValue& vibration_value) { | ||
| 746 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); | ||
| 747 | if (!controller.device->IsConnected()) { | ||
| 748 | return false; | ||
| 749 | } | ||
| 750 | |||
| 751 | if (!controller.device->IsVibrationEnabled(device_index)) { | ||
| 752 | if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f || | ||
| 753 | controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) { | ||
| 754 | // Send an empty vibration to stop any vibrations. | ||
| 755 | Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f}; | ||
| 756 | controller.device->SetVibration(device_index, vibration); | ||
| 757 | // Then reset the vibration value to its default value. | ||
| 758 | controller.vibration[device_index].latest_vibration_value = | ||
| 759 | Core::HID::DEFAULT_VIBRATION_VALUE; | ||
| 760 | } | ||
| 761 | |||
| 762 | return false; | ||
| 763 | } | ||
| 764 | |||
| 765 | if (!Settings::values.enable_accurate_vibrations.GetValue()) { | ||
| 766 | using std::chrono::duration_cast; | ||
| 767 | using std::chrono::milliseconds; | ||
| 768 | using std::chrono::steady_clock; | ||
| 769 | |||
| 770 | const auto now = steady_clock::now(); | ||
| 771 | |||
| 772 | // Filter out non-zero vibrations that are within 15ms of each other. | ||
| 773 | if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) && | ||
| 774 | duration_cast<milliseconds>( | ||
| 775 | now - controller.vibration[device_index].last_vibration_timepoint) < | ||
| 776 | milliseconds(15)) { | ||
| 777 | return false; | ||
| 778 | } | ||
| 779 | |||
| 780 | controller.vibration[device_index].last_vibration_timepoint = now; | ||
| 781 | } | ||
| 782 | |||
| 783 | Core::HID::VibrationValue vibration{ | ||
| 784 | vibration_value.low_amplitude, vibration_value.low_frequency, | ||
| 785 | vibration_value.high_amplitude, vibration_value.high_frequency}; | ||
| 786 | return controller.device->SetVibration(device_index, vibration); | ||
| 787 | } | ||
| 788 | |||
| 789 | void NPad::VibrateController(u64 aruid, | ||
| 790 | const Core::HID::VibrationDeviceHandle& vibration_device_handle, | ||
| 791 | const Core::HID::VibrationValue& vibration_value) { | ||
| 792 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { | ||
| 793 | return; | ||
| 794 | } | ||
| 795 | |||
| 796 | if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { | ||
| 797 | return; | ||
| 798 | } | ||
| 799 | |||
| 800 | auto& controller = GetControllerFromHandle(aruid, vibration_device_handle); | ||
| 801 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | ||
| 802 | |||
| 803 | if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) { | ||
| 804 | return; | ||
| 805 | } | ||
| 806 | |||
| 807 | if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) { | ||
| 808 | ASSERT_MSG(false, "DeviceIndex should never be None!"); | ||
| 809 | return; | ||
| 810 | } | ||
| 811 | |||
| 812 | // Some games try to send mismatched parameters in the device handle, block these. | ||
| 813 | if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && | ||
| 814 | (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight || | ||
| 815 | vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) || | ||
| 816 | (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight && | ||
| 817 | (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft || | ||
| 818 | vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) { | ||
| 819 | return; | ||
| 820 | } | ||
| 821 | |||
| 822 | // Filter out vibrations with equivalent values to reduce unnecessary state changes. | ||
| 823 | if (vibration_value.low_amplitude == | ||
| 824 | controller.vibration[device_index].latest_vibration_value.low_amplitude && | ||
| 825 | vibration_value.high_amplitude == | ||
| 826 | controller.vibration[device_index].latest_vibration_value.high_amplitude) { | ||
| 827 | return; | ||
| 828 | } | ||
| 829 | |||
| 830 | if (VibrateControllerAtIndex(aruid, controller.device->GetNpadIdType(), device_index, | ||
| 831 | vibration_value)) { | ||
| 832 | controller.vibration[device_index].latest_vibration_value = vibration_value; | ||
| 833 | } | ||
| 834 | } | ||
| 835 | |||
| 836 | void NPad::VibrateControllers( | ||
| 837 | u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, | ||
| 838 | std::span<const Core::HID::VibrationValue> vibration_values) { | ||
| 839 | if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { | ||
| 840 | return; | ||
| 841 | } | ||
| 842 | |||
| 843 | ASSERT_OR_EXECUTE_MSG( | ||
| 844 | vibration_device_handles.size() == vibration_values.size(), { return; }, | ||
| 845 | "The amount of device handles does not match with the amount of vibration values," | ||
| 846 | "this is undefined behavior!"); | ||
| 847 | |||
| 848 | for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) { | ||
| 849 | VibrateController(aruid, vibration_device_handles[i], vibration_values[i]); | ||
| 850 | } | ||
| 851 | } | ||
| 852 | |||
| 853 | Core::HID::VibrationValue NPad::GetLastVibration( | ||
| 854 | u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { | ||
| 855 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { | ||
| 856 | return {}; | ||
| 857 | } | ||
| 858 | |||
| 859 | const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle); | ||
| 860 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | ||
| 861 | return controller.vibration[device_index].latest_vibration_value; | ||
| 862 | } | ||
| 863 | |||
| 864 | void NPad::InitializeVibrationDevice( | ||
| 865 | const Core::HID::VibrationDeviceHandle& vibration_device_handle) { | ||
| 866 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { | ||
| 867 | return; | ||
| 868 | } | ||
| 869 | |||
| 870 | const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid(); | ||
| 871 | const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id); | ||
| 872 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | ||
| 873 | |||
| 874 | if (aruid == 0) { | ||
| 875 | return; | ||
| 876 | } | ||
| 877 | |||
| 878 | InitializeVibrationDeviceAtIndex(aruid, npad_index, device_index); | ||
| 879 | } | ||
| 880 | |||
| 881 | void NPad::InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id, | ||
| 882 | std::size_t device_index) { | ||
| 883 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); | ||
| 884 | if (!Settings::values.vibration_enabled.GetValue()) { | ||
| 885 | controller.vibration[device_index].device_mounted = false; | ||
| 886 | return; | ||
| 887 | } | ||
| 888 | |||
| 889 | controller.vibration[device_index].device_mounted = | ||
| 890 | controller.device->IsVibrationEnabled(device_index); | ||
| 891 | } | ||
| 892 | |||
| 893 | void NPad::SetPermitVibrationSession(bool permit_vibration_session) { | ||
| 894 | permit_vibration_session_enabled = permit_vibration_session; | ||
| 895 | } | ||
| 896 | |||
| 897 | bool NPad::IsVibrationDeviceMounted( | ||
| 898 | u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { | ||
| 899 | if (IsVibrationHandleValid(vibration_device_handle).IsError()) { | ||
| 900 | return false; | ||
| 901 | } | ||
| 902 | |||
| 903 | const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle); | ||
| 904 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); | ||
| 905 | return controller.vibration[device_index].device_mounted; | ||
| 906 | } | ||
| 907 | |||
| 908 | Result NPad::AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, | 745 | Result NPad::AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, |
| 909 | Core::HID::NpadIdType npad_id) { | 746 | Core::HID::NpadIdType npad_id) { |
| 910 | std::scoped_lock lock{mutex}; | 747 | std::scoped_lock lock{mutex}; |
| @@ -936,11 +773,6 @@ Result NPad::DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id) { | |||
| 936 | 773 | ||
| 937 | LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); | 774 | LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); |
| 938 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); | 775 | auto& controller = GetControllerFromNpadIdType(aruid, npad_id); |
| 939 | for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { | ||
| 940 | // Send an empty vibration to stop any vibrations. | ||
| 941 | VibrateControllerAtIndex(aruid, npad_id, device_idx, {}); | ||
| 942 | controller.vibration[device_idx].device_mounted = false; | ||
| 943 | } | ||
| 944 | 776 | ||
| 945 | auto* shared_memory = controller.shared_memory; | 777 | auto* shared_memory = controller.shared_memory; |
| 946 | // Don't reset shared_memory->assignment_mode this value is persistent | 778 | // Don't reset shared_memory->assignment_mode this value is persistent |
| @@ -1232,26 +1064,28 @@ Result NPad::RegisterAppletResourceUserId(u64 aruid) { | |||
| 1232 | } | 1064 | } |
| 1233 | 1065 | ||
| 1234 | void NPad::UnregisterAppletResourceUserId(u64 aruid) { | 1066 | void NPad::UnregisterAppletResourceUserId(u64 aruid) { |
| 1067 | // TODO: Remove this once abstract pad is emulated properly | ||
| 1068 | const auto aruid_index = npad_resource.GetIndexFromAruid(aruid); | ||
| 1069 | for (auto& controller : controller_data[aruid_index]) { | ||
| 1070 | controller.is_connected = false; | ||
| 1071 | controller.shared_memory = nullptr; | ||
| 1072 | } | ||
| 1073 | |||
| 1235 | npad_resource.UnregisterAppletResourceUserId(aruid); | 1074 | npad_resource.UnregisterAppletResourceUserId(aruid); |
| 1236 | } | 1075 | } |
| 1237 | 1076 | ||
| 1238 | void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource, | 1077 | void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource, |
| 1239 | std::recursive_mutex* shared_mutex) { | 1078 | std::recursive_mutex* shared_mutex, |
| 1079 | std::shared_ptr<HandheldConfig> handheld_config) { | ||
| 1240 | applet_resource_holder.applet_resource = resource; | 1080 | applet_resource_holder.applet_resource = resource; |
| 1241 | applet_resource_holder.shared_mutex = shared_mutex; | 1081 | applet_resource_holder.shared_mutex = shared_mutex; |
| 1242 | applet_resource_holder.shared_npad_resource = &npad_resource; | 1082 | applet_resource_holder.shared_npad_resource = &npad_resource; |
| 1243 | } | 1083 | applet_resource_holder.handheld_config = handheld_config; |
| 1244 | |||
| 1245 | NPad::NpadControllerData& NPad::GetControllerFromHandle( | ||
| 1246 | u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) { | ||
| 1247 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | ||
| 1248 | return GetControllerFromNpadIdType(aruid, npad_id); | ||
| 1249 | } | ||
| 1250 | 1084 | ||
| 1251 | const NPad::NpadControllerData& NPad::GetControllerFromHandle( | 1085 | for (auto& abstract_pad : abstracted_pads) { |
| 1252 | u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const { | 1086 | abstract_pad.SetExternals(&applet_resource_holder, nullptr, nullptr, nullptr, nullptr, |
| 1253 | const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id); | 1087 | &vibration_handler, &hid_core); |
| 1254 | return GetControllerFromNpadIdType(aruid, npad_id); | 1088 | } |
| 1255 | } | 1089 | } |
| 1256 | 1090 | ||
| 1257 | NPad::NpadControllerData& NPad::GetControllerFromHandle( | 1091 | NPad::NpadControllerData& NPad::GetControllerFromHandle( |
| @@ -1389,4 +1223,97 @@ Result NPad::GetLastActiveNpad(Core::HID::NpadIdType& out_npad_id) const { | |||
| 1389 | return ResultSuccess; | 1223 | return ResultSuccess; |
| 1390 | } | 1224 | } |
| 1391 | 1225 | ||
| 1226 | NpadVibration* NPad::GetVibrationHandler() { | ||
| 1227 | return &vibration_handler; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | std::vector<NpadVibrationBase*> NPad::GetAllVibrationDevices() { | ||
| 1231 | std::vector<NpadVibrationBase*> vibration_devices; | ||
| 1232 | |||
| 1233 | for (auto& abstract_pad : abstracted_pads) { | ||
| 1234 | auto* left_device = abstract_pad.GetVibrationDevice(Core::HID::DeviceIndex::Left); | ||
| 1235 | auto* right_device = abstract_pad.GetVibrationDevice(Core::HID::DeviceIndex::Right); | ||
| 1236 | auto* n64_device = abstract_pad.GetGCVibrationDevice(); | ||
| 1237 | auto* gc_device = abstract_pad.GetGCVibrationDevice(); | ||
| 1238 | |||
| 1239 | if (left_device != nullptr) { | ||
| 1240 | vibration_devices.emplace_back(left_device); | ||
| 1241 | } | ||
| 1242 | if (right_device != nullptr) { | ||
| 1243 | vibration_devices.emplace_back(right_device); | ||
| 1244 | } | ||
| 1245 | if (n64_device != nullptr) { | ||
| 1246 | vibration_devices.emplace_back(n64_device); | ||
| 1247 | } | ||
| 1248 | if (gc_device != nullptr) { | ||
| 1249 | vibration_devices.emplace_back(gc_device); | ||
| 1250 | } | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | return vibration_devices; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | NpadVibrationBase* NPad::GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) { | ||
| 1257 | if (IsVibrationHandleValid(handle).IsError()) { | ||
| 1258 | return nullptr; | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id)); | ||
| 1262 | const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type); | ||
| 1263 | if (style_inde == Core::HID::NpadStyleIndex::GameCube) { | ||
| 1264 | return abstracted_pads[npad_index].GetGCVibrationDevice(); | ||
| 1265 | } | ||
| 1266 | if (style_inde == Core::HID::NpadStyleIndex::N64) { | ||
| 1267 | return abstracted_pads[npad_index].GetN64VibrationDevice(); | ||
| 1268 | } | ||
| 1269 | return abstracted_pads[npad_index].GetVibrationDevice(handle.device_index); | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | NpadN64VibrationDevice* NPad::GetN64VibrationDevice( | ||
| 1273 | const Core::HID::VibrationDeviceHandle& handle) { | ||
| 1274 | if (IsVibrationHandleValid(handle).IsError()) { | ||
| 1275 | return nullptr; | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id)); | ||
| 1279 | const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type); | ||
| 1280 | if (style_inde != Core::HID::NpadStyleIndex::N64) { | ||
| 1281 | return nullptr; | ||
| 1282 | } | ||
| 1283 | return abstracted_pads[npad_index].GetN64VibrationDevice(); | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | NpadVibrationDevice* NPad::GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) { | ||
| 1287 | if (IsVibrationHandleValid(handle).IsError()) { | ||
| 1288 | return nullptr; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id)); | ||
| 1292 | const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type); | ||
| 1293 | if (style_inde == Core::HID::NpadStyleIndex::GameCube || | ||
| 1294 | style_inde == Core::HID::NpadStyleIndex::N64) { | ||
| 1295 | return nullptr; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | return abstracted_pads[npad_index].GetVibrationDevice(handle.device_index); | ||
| 1299 | } | ||
| 1300 | |||
| 1301 | NpadGcVibrationDevice* NPad::GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) { | ||
| 1302 | if (IsVibrationHandleValid(handle).IsError()) { | ||
| 1303 | return nullptr; | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id)); | ||
| 1307 | const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type); | ||
| 1308 | if (style_inde != Core::HID::NpadStyleIndex::GameCube) { | ||
| 1309 | return nullptr; | ||
| 1310 | } | ||
| 1311 | return abstracted_pads[npad_index].GetGCVibrationDevice(); | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | void NPad::UpdateHandheldAbstractState() { | ||
| 1315 | std::scoped_lock lock{mutex}; | ||
| 1316 | abstracted_pads[NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld)].Update(); | ||
| 1317 | } | ||
| 1318 | |||
| 1392 | } // namespace Service::HID | 1319 | } // namespace Service::HID |
diff --git a/src/hid_core/resources/npad/npad.h b/src/hid_core/resources/npad/npad.h index 01f3dabb1..18b25c688 100644 --- a/src/hid_core/resources/npad/npad.h +++ b/src/hid_core/resources/npad/npad.h | |||
| @@ -10,9 +10,15 @@ | |||
| 10 | 10 | ||
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "hid_core/hid_types.h" | 12 | #include "hid_core/hid_types.h" |
| 13 | #include "hid_core/resources/abstracted_pad/abstract_pad.h" | ||
| 13 | #include "hid_core/resources/controller_base.h" | 14 | #include "hid_core/resources/controller_base.h" |
| 14 | #include "hid_core/resources/npad/npad_resource.h" | 15 | #include "hid_core/resources/npad/npad_resource.h" |
| 15 | #include "hid_core/resources/npad/npad_types.h" | 16 | #include "hid_core/resources/npad/npad_types.h" |
| 17 | #include "hid_core/resources/npad/npad_vibration.h" | ||
| 18 | #include "hid_core/resources/vibration/gc_vibration_device.h" | ||
| 19 | #include "hid_core/resources/vibration/n64_vibration_device.h" | ||
| 20 | #include "hid_core/resources/vibration/vibration_base.h" | ||
| 21 | #include "hid_core/resources/vibration/vibration_device.h" | ||
| 16 | 22 | ||
| 17 | namespace Core::HID { | 23 | namespace Core::HID { |
| 18 | class EmulatedController; | 24 | class EmulatedController; |
| @@ -32,6 +38,7 @@ union Result; | |||
| 32 | 38 | ||
| 33 | namespace Service::HID { | 39 | namespace Service::HID { |
| 34 | class AppletResource; | 40 | class AppletResource; |
| 41 | struct HandheldConfig; | ||
| 35 | struct NpadInternalState; | 42 | struct NpadInternalState; |
| 36 | struct NpadSixAxisSensorLifo; | 43 | struct NpadSixAxisSensorLifo; |
| 37 | struct NpadSharedMemoryFormat; | 44 | struct NpadSharedMemoryFormat; |
| @@ -68,31 +75,6 @@ public: | |||
| 68 | bool SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, | 75 | bool SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id, |
| 69 | NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode); | 76 | NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode); |
| 70 | 77 | ||
| 71 | bool VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id, | ||
| 72 | std::size_t device_index, | ||
| 73 | const Core::HID::VibrationValue& vibration_value); | ||
| 74 | |||
| 75 | void VibrateController(u64 aruid, | ||
| 76 | const Core::HID::VibrationDeviceHandle& vibration_device_handle, | ||
| 77 | const Core::HID::VibrationValue& vibration_value); | ||
| 78 | |||
| 79 | void VibrateControllers( | ||
| 80 | u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles, | ||
| 81 | std::span<const Core::HID::VibrationValue> vibration_values); | ||
| 82 | |||
| 83 | Core::HID::VibrationValue GetLastVibration( | ||
| 84 | u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; | ||
| 85 | |||
| 86 | void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle); | ||
| 87 | |||
| 88 | void InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id, | ||
| 89 | std::size_t device_index); | ||
| 90 | |||
| 91 | void SetPermitVibrationSession(bool permit_vibration_session); | ||
| 92 | |||
| 93 | bool IsVibrationDeviceMounted( | ||
| 94 | u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; | ||
| 95 | |||
| 96 | Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, | 78 | Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event, |
| 97 | Core::HID::NpadIdType npad_id); | 79 | Core::HID::NpadIdType npad_id); |
| 98 | 80 | ||
| @@ -145,7 +127,8 @@ public: | |||
| 145 | Result RegisterAppletResourceUserId(u64 aruid); | 127 | Result RegisterAppletResourceUserId(u64 aruid); |
| 146 | void UnregisterAppletResourceUserId(u64 aruid); | 128 | void UnregisterAppletResourceUserId(u64 aruid); |
| 147 | void SetNpadExternals(std::shared_ptr<AppletResource> resource, | 129 | void SetNpadExternals(std::shared_ptr<AppletResource> resource, |
| 148 | std::recursive_mutex* shared_mutex); | 130 | std::recursive_mutex* shared_mutex, |
| 131 | std::shared_ptr<HandheldConfig> handheld_config); | ||
| 149 | 132 | ||
| 150 | AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); | 133 | AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); |
| 151 | 134 | ||
| @@ -161,18 +144,20 @@ public: | |||
| 161 | 144 | ||
| 162 | Result GetLastActiveNpad(Core::HID::NpadIdType& out_npad_id) const; | 145 | Result GetLastActiveNpad(Core::HID::NpadIdType& out_npad_id) const; |
| 163 | 146 | ||
| 164 | private: | 147 | NpadVibration* GetVibrationHandler(); |
| 165 | struct VibrationData { | 148 | std::vector<NpadVibrationBase*> GetAllVibrationDevices(); |
| 166 | bool device_mounted{}; | 149 | NpadVibrationBase* GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle); |
| 167 | Core::HID::VibrationValue latest_vibration_value{}; | 150 | NpadN64VibrationDevice* GetN64VibrationDevice(const Core::HID::VibrationDeviceHandle& handle); |
| 168 | std::chrono::steady_clock::time_point last_vibration_timepoint{}; | 151 | NpadVibrationDevice* GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle); |
| 169 | }; | 152 | NpadGcVibrationDevice* GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle); |
| 170 | 153 | ||
| 154 | void UpdateHandheldAbstractState(); | ||
| 155 | |||
| 156 | private: | ||
| 171 | struct NpadControllerData { | 157 | struct NpadControllerData { |
| 172 | NpadInternalState* shared_memory = nullptr; | 158 | NpadInternalState* shared_memory = nullptr; |
| 173 | Core::HID::EmulatedController* device = nullptr; | 159 | Core::HID::EmulatedController* device = nullptr; |
| 174 | 160 | ||
| 175 | std::array<VibrationData, 2> vibration{}; | ||
| 176 | bool is_connected{}; | 161 | bool is_connected{}; |
| 177 | 162 | ||
| 178 | // Dual joycons can have only one side connected | 163 | // Dual joycons can have only one side connected |
| @@ -192,10 +177,6 @@ private: | |||
| 192 | void WriteEmptyEntry(NpadInternalState* npad); | 177 | void WriteEmptyEntry(NpadInternalState* npad); |
| 193 | 178 | ||
| 194 | NpadControllerData& GetControllerFromHandle( | 179 | NpadControllerData& GetControllerFromHandle( |
| 195 | u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle); | ||
| 196 | const NpadControllerData& GetControllerFromHandle( | ||
| 197 | u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const; | ||
| 198 | NpadControllerData& GetControllerFromHandle( | ||
| 199 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle); | 180 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle); |
| 200 | const NpadControllerData& GetControllerFromHandle( | 181 | const NpadControllerData& GetControllerFromHandle( |
| 201 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const; | 182 | u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle) const; |
| @@ -215,11 +196,13 @@ private: | |||
| 215 | mutable std::mutex mutex; | 196 | mutable std::mutex mutex; |
| 216 | NPadResource npad_resource; | 197 | NPadResource npad_resource; |
| 217 | AppletResourceHolder applet_resource_holder{}; | 198 | AppletResourceHolder applet_resource_holder{}; |
| 199 | std::array<AbstractPad, MaxSupportedNpadIdTypes> abstracted_pads; | ||
| 200 | NpadVibration vibration_handler{}; | ||
| 201 | |||
| 218 | Kernel::KEvent* input_event{nullptr}; | 202 | Kernel::KEvent* input_event{nullptr}; |
| 219 | std::mutex* input_mutex{nullptr}; | 203 | std::mutex* input_mutex{nullptr}; |
| 220 | 204 | ||
| 221 | std::atomic<u64> press_state{}; | 205 | std::atomic<u64> press_state{}; |
| 222 | bool permit_vibration_session_enabled; | ||
| 223 | std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax> | 206 | std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax> |
| 224 | controller_data{}; | 207 | controller_data{}; |
| 225 | }; | 208 | }; |
diff --git a/src/hid_core/resources/npad/npad_types.h b/src/hid_core/resources/npad/npad_types.h index fd86c8e40..92700d69a 100644 --- a/src/hid_core/resources/npad/npad_types.h +++ b/src/hid_core/resources/npad/npad_types.h | |||
| @@ -8,6 +8,10 @@ | |||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "hid_core/hid_types.h" | 9 | #include "hid_core/hid_types.h" |
| 10 | 10 | ||
| 11 | namespace Core::HID { | ||
| 12 | class EmulatedController; | ||
| 13 | } | ||
| 14 | |||
| 11 | namespace Service::HID { | 15 | namespace Service::HID { |
| 12 | static constexpr std::size_t MaxSupportedNpadIdTypes = 10; | 16 | static constexpr std::size_t MaxSupportedNpadIdTypes = 10; |
| 13 | static constexpr std::size_t StyleIndexCount = 7; | 17 | static constexpr std::size_t StyleIndexCount = 7; |
| @@ -348,7 +352,7 @@ struct IAbstractedPad { | |||
| 348 | u8 indicator; | 352 | u8 indicator; |
| 349 | std::vector<f32> virtual_six_axis_sensor_acceleration; | 353 | std::vector<f32> virtual_six_axis_sensor_acceleration; |
| 350 | std::vector<f32> virtual_six_axis_sensor_angle; | 354 | std::vector<f32> virtual_six_axis_sensor_angle; |
| 351 | u64 xcd_handle; | 355 | Core::HID::EmulatedController* xcd_handle; |
| 352 | u64 color; | 356 | u64 color; |
| 353 | }; | 357 | }; |
| 354 | } // namespace Service::HID | 358 | } // namespace Service::HID |
diff --git a/src/hid_core/resources/npad/npad_vibration.cpp b/src/hid_core/resources/npad/npad_vibration.cpp index 7056e8eab..05aad4c54 100644 --- a/src/hid_core/resources/npad/npad_vibration.cpp +++ b/src/hid_core/resources/npad/npad_vibration.cpp | |||
| @@ -77,4 +77,8 @@ Result NpadVibration::EndPermitVibrationSession() { | |||
| 77 | return ResultSuccess; | 77 | return ResultSuccess; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | u64 NpadVibration::GetSessionAruid() const { | ||
| 81 | return session_aruid; | ||
| 82 | } | ||
| 83 | |||
| 80 | } // namespace Service::HID | 84 | } // namespace Service::HID |
diff --git a/src/hid_core/resources/npad/npad_vibration.h b/src/hid_core/resources/npad/npad_vibration.h index 0748aeffc..d5a95f2a0 100644 --- a/src/hid_core/resources/npad/npad_vibration.h +++ b/src/hid_core/resources/npad/npad_vibration.h | |||
| @@ -25,6 +25,8 @@ public: | |||
| 25 | Result BeginPermitVibrationSession(u64 aruid); | 25 | Result BeginPermitVibrationSession(u64 aruid); |
| 26 | Result EndPermitVibrationSession(); | 26 | Result EndPermitVibrationSession(); |
| 27 | 27 | ||
| 28 | u64 GetSessionAruid() const; | ||
| 29 | |||
| 28 | private: | 30 | private: |
| 29 | f32 volume{}; | 31 | f32 volume{}; |
| 30 | u64 session_aruid{}; | 32 | u64 session_aruid{}; |
diff --git a/src/hid_core/resources/vibration/gc_vibration_device.cpp b/src/hid_core/resources/vibration/gc_vibration_device.cpp index f01f81b9a..ad42b9d66 100644 --- a/src/hid_core/resources/vibration/gc_vibration_device.cpp +++ b/src/hid_core/resources/vibration/gc_vibration_device.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include "hid_core/frontend/emulated_controller.h" | ||
| 4 | #include "hid_core/hid_result.h" | 5 | #include "hid_core/hid_result.h" |
| 5 | #include "hid_core/resources/npad/npad_types.h" | 6 | #include "hid_core/resources/npad/npad_types.h" |
| 6 | #include "hid_core/resources/npad/npad_vibration.h" | 7 | #include "hid_core/resources/npad/npad_vibration.h" |
| @@ -10,24 +11,25 @@ namespace Service::HID { | |||
| 10 | 11 | ||
| 11 | NpadGcVibrationDevice::NpadGcVibrationDevice() {} | 12 | NpadGcVibrationDevice::NpadGcVibrationDevice() {} |
| 12 | 13 | ||
| 13 | Result NpadGcVibrationDevice::IncrementRefCounter() { | 14 | Result NpadGcVibrationDevice::Activate() { |
| 14 | if (ref_counter == 0 && is_mounted) { | 15 | if (ref_counter == 0 && is_mounted) { |
| 15 | f32 volume = 1.0f; | 16 | f32 volume = 1.0f; |
| 16 | const auto result = vibration_handler->GetVibrationVolume(volume); | 17 | const auto result = vibration_handler->GetVibrationVolume(volume); |
| 17 | if (result.IsSuccess()) { | 18 | if (result.IsSuccess()) { |
| 18 | // TODO: SendVibrationGcErmCommand | 19 | xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop); |
| 19 | } | 20 | } |
| 20 | } | 21 | } |
| 22 | |||
| 21 | ref_counter++; | 23 | ref_counter++; |
| 22 | return ResultSuccess; | 24 | return ResultSuccess; |
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | Result NpadGcVibrationDevice::DecrementRefCounter() { | 27 | Result NpadGcVibrationDevice::Deactivate() { |
| 26 | if (ref_counter == 1 && !is_mounted) { | 28 | if (ref_counter == 1 && is_mounted) { |
| 27 | f32 volume = 1.0f; | 29 | f32 volume = 1.0f; |
| 28 | const auto result = vibration_handler->GetVibrationVolume(volume); | 30 | const auto result = vibration_handler->GetVibrationVolume(volume); |
| 29 | if (result.IsSuccess()) { | 31 | if (result.IsSuccess()) { |
| 30 | // TODO: SendVibrationGcErmCommand | 32 | xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop); |
| 31 | } | 33 | } |
| 32 | } | 34 | } |
| 33 | 35 | ||
| @@ -38,6 +40,48 @@ Result NpadGcVibrationDevice::DecrementRefCounter() { | |||
| 38 | return ResultSuccess; | 40 | return ResultSuccess; |
| 39 | } | 41 | } |
| 40 | 42 | ||
| 43 | Result NpadGcVibrationDevice::Mount(IAbstractedPad& abstracted_pad, u32 slot, | ||
| 44 | NpadVibration* handler) { | ||
| 45 | if (!abstracted_pad.internal_flags.is_connected) { | ||
| 46 | return ResultSuccess; | ||
| 47 | } | ||
| 48 | |||
| 49 | // TODO: This device doesn't use a xcd handle instead has an GC adapter handle. This is just to | ||
| 50 | // keep compatibility with the front end. | ||
| 51 | xcd_handle = abstracted_pad.xcd_handle; | ||
| 52 | adapter_slot = slot; | ||
| 53 | vibration_handler = handler; | ||
| 54 | is_mounted = true; | ||
| 55 | |||
| 56 | if (ref_counter == 0) { | ||
| 57 | return ResultSuccess; | ||
| 58 | } | ||
| 59 | |||
| 60 | f32 volume{1.0f}; | ||
| 61 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 62 | if (result.IsSuccess()) { | ||
| 63 | xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop); | ||
| 64 | } | ||
| 65 | |||
| 66 | return ResultSuccess; | ||
| 67 | } | ||
| 68 | |||
| 69 | Result NpadGcVibrationDevice::Unmount() { | ||
| 70 | if (ref_counter == 0 || !is_mounted) { | ||
| 71 | is_mounted = false; | ||
| 72 | return ResultSuccess; | ||
| 73 | } | ||
| 74 | |||
| 75 | f32 volume{1.0f}; | ||
| 76 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 77 | if (result.IsSuccess()) { | ||
| 78 | xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop); | ||
| 79 | } | ||
| 80 | |||
| 81 | is_mounted = false; | ||
| 82 | return ResultSuccess; | ||
| 83 | } | ||
| 84 | |||
| 41 | Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command) { | 85 | Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command) { |
| 42 | if (!is_mounted) { | 86 | if (!is_mounted) { |
| 43 | return ResultSuccess; | 87 | return ResultSuccess; |
| @@ -55,7 +99,7 @@ Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcEr | |||
| 55 | return ResultSuccess; | 99 | return ResultSuccess; |
| 56 | } | 100 | } |
| 57 | } | 101 | } |
| 58 | // TODO: SendVibrationGcErmCommand | 102 | xcd_handle->SetVibration(adapter_slot, command); |
| 59 | return ResultSuccess; | 103 | return ResultSuccess; |
| 60 | } | 104 | } |
| 61 | 105 | ||
diff --git a/src/hid_core/resources/vibration/gc_vibration_device.h b/src/hid_core/resources/vibration/gc_vibration_device.h index 87abca57d..c624cbb28 100644 --- a/src/hid_core/resources/vibration/gc_vibration_device.h +++ b/src/hid_core/resources/vibration/gc_vibration_device.h | |||
| @@ -20,12 +20,18 @@ class NpadGcVibrationDevice final : public NpadVibrationBase { | |||
| 20 | public: | 20 | public: |
| 21 | explicit NpadGcVibrationDevice(); | 21 | explicit NpadGcVibrationDevice(); |
| 22 | 22 | ||
| 23 | Result IncrementRefCounter() override; | 23 | Result Activate() override; |
| 24 | Result DecrementRefCounter() override; | 24 | Result Deactivate() override; |
| 25 | |||
| 26 | Result Mount(IAbstractedPad& abstracted_pad, u32 slot, NpadVibration* handler); | ||
| 27 | Result Unmount(); | ||
| 25 | 28 | ||
| 26 | Result SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command); | 29 | Result SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command); |
| 27 | 30 | ||
| 28 | Result GetActualVibrationGcErmCommand(Core::HID::VibrationGcErmCommand& out_command); | 31 | Result GetActualVibrationGcErmCommand(Core::HID::VibrationGcErmCommand& out_command); |
| 29 | Result SendVibrationNotificationPattern(Core::HID::VibrationGcErmCommand command); | 32 | Result SendVibrationNotificationPattern(Core::HID::VibrationGcErmCommand command); |
| 33 | |||
| 34 | private: | ||
| 35 | u32 adapter_slot; | ||
| 30 | }; | 36 | }; |
| 31 | } // namespace Service::HID | 37 | } // namespace Service::HID |
diff --git a/src/hid_core/resources/vibration/n64_vibration_device.cpp b/src/hid_core/resources/vibration/n64_vibration_device.cpp index 639f87abf..94ad37c8f 100644 --- a/src/hid_core/resources/vibration/n64_vibration_device.cpp +++ b/src/hid_core/resources/vibration/n64_vibration_device.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include "hid_core/frontend/emulated_controller.h" | ||
| 4 | #include "hid_core/hid_result.h" | 5 | #include "hid_core/hid_result.h" |
| 5 | #include "hid_core/resources/npad/npad_types.h" | 6 | #include "hid_core/resources/npad/npad_types.h" |
| 6 | #include "hid_core/resources/npad/npad_vibration.h" | 7 | #include "hid_core/resources/npad/npad_vibration.h" |
| @@ -10,12 +11,12 @@ namespace Service::HID { | |||
| 10 | 11 | ||
| 11 | NpadN64VibrationDevice::NpadN64VibrationDevice() {} | 12 | NpadN64VibrationDevice::NpadN64VibrationDevice() {} |
| 12 | 13 | ||
| 13 | Result NpadN64VibrationDevice::IncrementRefCounter() { | 14 | Result NpadN64VibrationDevice::Activate() { |
| 14 | if (ref_counter == 0 && is_mounted) { | 15 | if (ref_counter == 0 && is_mounted) { |
| 15 | f32 volume = 1.0f; | 16 | f32 volume = 1.0f; |
| 16 | const auto result = vibration_handler->GetVibrationVolume(volume); | 17 | const auto result = vibration_handler->GetVibrationVolume(volume); |
| 17 | if (result.IsSuccess()) { | 18 | if (result.IsSuccess()) { |
| 18 | // TODO: SendVibrationInBool | 19 | xcd_handle->SetVibration(false); |
| 19 | } | 20 | } |
| 20 | } | 21 | } |
| 21 | 22 | ||
| @@ -23,19 +24,12 @@ Result NpadN64VibrationDevice::IncrementRefCounter() { | |||
| 23 | return ResultSuccess; | 24 | return ResultSuccess; |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | Result NpadN64VibrationDevice::DecrementRefCounter() { | 27 | Result NpadN64VibrationDevice::Deactivate() { |
| 27 | if (ref_counter == 1) { | 28 | if (ref_counter == 1 && is_mounted) { |
| 28 | if (!is_mounted) { | ||
| 29 | ref_counter = 0; | ||
| 30 | if (is_mounted != false) { | ||
| 31 | // TODO: SendVibrationInBool | ||
| 32 | } | ||
| 33 | return ResultSuccess; | ||
| 34 | } | ||
| 35 | f32 volume = 1.0f; | 29 | f32 volume = 1.0f; |
| 36 | const auto result = vibration_handler->GetVibrationVolume(volume); | 30 | const auto result = vibration_handler->GetVibrationVolume(volume); |
| 37 | if (result.IsSuccess()) { | 31 | if (result.IsSuccess()) { |
| 38 | // TODO | 32 | xcd_handle->SetVibration(false); |
| 39 | } | 33 | } |
| 40 | } | 34 | } |
| 41 | 35 | ||
| @@ -46,6 +40,43 @@ Result NpadN64VibrationDevice::DecrementRefCounter() { | |||
| 46 | return ResultSuccess; | 40 | return ResultSuccess; |
| 47 | } | 41 | } |
| 48 | 42 | ||
| 43 | Result NpadN64VibrationDevice::Mount(IAbstractedPad& abstracted_pad, NpadVibration* handler) { | ||
| 44 | if (!abstracted_pad.internal_flags.is_connected) { | ||
| 45 | return ResultSuccess; | ||
| 46 | } | ||
| 47 | xcd_handle = abstracted_pad.xcd_handle; | ||
| 48 | vibration_handler = handler; | ||
| 49 | is_mounted = true; | ||
| 50 | |||
| 51 | if (ref_counter == 0) { | ||
| 52 | return ResultSuccess; | ||
| 53 | } | ||
| 54 | |||
| 55 | f32 volume{1.0f}; | ||
| 56 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 57 | if (result.IsSuccess()) { | ||
| 58 | xcd_handle->SetVibration(false); | ||
| 59 | } | ||
| 60 | |||
| 61 | return ResultSuccess; | ||
| 62 | } | ||
| 63 | |||
| 64 | Result NpadN64VibrationDevice::Unmount() { | ||
| 65 | if (ref_counter == 0 || !is_mounted) { | ||
| 66 | is_mounted = false; | ||
| 67 | return ResultSuccess; | ||
| 68 | } | ||
| 69 | |||
| 70 | f32 volume{1.0f}; | ||
| 71 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 72 | if (result.IsSuccess()) { | ||
| 73 | xcd_handle->SetVibration(false); | ||
| 74 | } | ||
| 75 | |||
| 76 | is_mounted = false; | ||
| 77 | return ResultSuccess; | ||
| 78 | } | ||
| 79 | |||
| 49 | Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) { | 80 | Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) { |
| 50 | if (ref_counter < 1) { | 81 | if (ref_counter < 1) { |
| 51 | return ResultVibrationNotInitialized; | 82 | return ResultVibrationNotInitialized; |
| @@ -56,7 +87,7 @@ Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) { | |||
| 56 | if (result.IsError()) { | 87 | if (result.IsError()) { |
| 57 | return result; | 88 | return result; |
| 58 | } | 89 | } |
| 59 | // TODO: SendVibrationInBool | 90 | xcd_handle->SetVibration(false); |
| 60 | } | 91 | } |
| 61 | return ResultSuccess; | 92 | return ResultSuccess; |
| 62 | } | 93 | } |
diff --git a/src/hid_core/resources/vibration/n64_vibration_device.h b/src/hid_core/resources/vibration/n64_vibration_device.h index 54e6efc1a..09de7701c 100644 --- a/src/hid_core/resources/vibration/n64_vibration_device.h +++ b/src/hid_core/resources/vibration/n64_vibration_device.h | |||
| @@ -14,14 +14,18 @@ | |||
| 14 | 14 | ||
| 15 | namespace Service::HID { | 15 | namespace Service::HID { |
| 16 | class NpadVibration; | 16 | class NpadVibration; |
| 17 | struct IAbstractedPad; | ||
| 17 | 18 | ||
| 18 | /// Handles Npad request from HID interfaces | 19 | /// Handles Npad request from HID interfaces |
| 19 | class NpadN64VibrationDevice final : public NpadVibrationBase { | 20 | class NpadN64VibrationDevice final : public NpadVibrationBase { |
| 20 | public: | 21 | public: |
| 21 | explicit NpadN64VibrationDevice(); | 22 | explicit NpadN64VibrationDevice(); |
| 22 | 23 | ||
| 23 | Result IncrementRefCounter() override; | 24 | Result Activate() override; |
| 24 | Result DecrementRefCounter() override; | 25 | Result Deactivate() override; |
| 26 | |||
| 27 | Result Mount(IAbstractedPad& abstracted_pad, NpadVibration* handler); | ||
| 28 | Result Unmount(); | ||
| 25 | 29 | ||
| 26 | Result SendValueInBool(bool is_vibrating); | 30 | Result SendValueInBool(bool is_vibrating); |
| 27 | Result SendVibrationNotificationPattern(u32 pattern); | 31 | Result SendVibrationNotificationPattern(u32 pattern); |
diff --git a/src/hid_core/resources/vibration/vibration_base.cpp b/src/hid_core/resources/vibration/vibration_base.cpp index 350f349c2..f28d30406 100644 --- a/src/hid_core/resources/vibration/vibration_base.cpp +++ b/src/hid_core/resources/vibration/vibration_base.cpp | |||
| @@ -10,12 +10,12 @@ namespace Service::HID { | |||
| 10 | 10 | ||
| 11 | NpadVibrationBase::NpadVibrationBase() {} | 11 | NpadVibrationBase::NpadVibrationBase() {} |
| 12 | 12 | ||
| 13 | Result NpadVibrationBase::IncrementRefCounter() { | 13 | Result NpadVibrationBase::Activate() { |
| 14 | ref_counter++; | 14 | ref_counter++; |
| 15 | return ResultSuccess; | 15 | return ResultSuccess; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | Result NpadVibrationBase::DecrementRefCounter() { | 18 | Result NpadVibrationBase::Deactivate() { |
| 19 | if (ref_counter > 0) { | 19 | if (ref_counter > 0) { |
| 20 | ref_counter--; | 20 | ref_counter--; |
| 21 | } | 21 | } |
diff --git a/src/hid_core/resources/vibration/vibration_base.h b/src/hid_core/resources/vibration/vibration_base.h index c6c5fc4d9..69c26e669 100644 --- a/src/hid_core/resources/vibration/vibration_base.h +++ b/src/hid_core/resources/vibration/vibration_base.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | #include "common/common_types.h" | 6 | #include "common/common_types.h" |
| 7 | #include "core/hle/result.h" | 7 | #include "core/hle/result.h" |
| 8 | 8 | ||
| 9 | namespace Core::HID { | ||
| 10 | class EmulatedController; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace Service::HID { | 13 | namespace Service::HID { |
| 10 | class NpadVibration; | 14 | class NpadVibration; |
| 11 | 15 | ||
| @@ -14,13 +18,13 @@ class NpadVibrationBase { | |||
| 14 | public: | 18 | public: |
| 15 | explicit NpadVibrationBase(); | 19 | explicit NpadVibrationBase(); |
| 16 | 20 | ||
| 17 | virtual Result IncrementRefCounter(); | 21 | virtual Result Activate(); |
| 18 | virtual Result DecrementRefCounter(); | 22 | virtual Result Deactivate(); |
| 19 | 23 | ||
| 20 | bool IsVibrationMounted() const; | 24 | bool IsVibrationMounted() const; |
| 21 | 25 | ||
| 22 | protected: | 26 | protected: |
| 23 | u64 xcd_handle{}; | 27 | Core::HID::EmulatedController* xcd_handle{nullptr}; |
| 24 | s32 ref_counter{}; | 28 | s32 ref_counter{}; |
| 25 | bool is_mounted{}; | 29 | bool is_mounted{}; |
| 26 | NpadVibration* vibration_handler{nullptr}; | 30 | NpadVibration* vibration_handler{nullptr}; |
diff --git a/src/hid_core/resources/vibration/vibration_device.cpp b/src/hid_core/resources/vibration/vibration_device.cpp index 888c3a7ed..08b14591f 100644 --- a/src/hid_core/resources/vibration/vibration_device.cpp +++ b/src/hid_core/resources/vibration/vibration_device.cpp | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | 2 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 3 | 3 | ||
| 4 | #include "hid_core/frontend/emulated_controller.h" | ||
| 4 | #include "hid_core/hid_result.h" | 5 | #include "hid_core/hid_result.h" |
| 5 | #include "hid_core/resources/npad/npad_types.h" | 6 | #include "hid_core/resources/npad/npad_types.h" |
| 6 | #include "hid_core/resources/npad/npad_vibration.h" | 7 | #include "hid_core/resources/npad/npad_vibration.h" |
| @@ -10,12 +11,30 @@ namespace Service::HID { | |||
| 10 | 11 | ||
| 11 | NpadVibrationDevice::NpadVibrationDevice() {} | 12 | NpadVibrationDevice::NpadVibrationDevice() {} |
| 12 | 13 | ||
| 13 | Result NpadVibrationDevice::IncrementRefCounter() { | 14 | Result NpadVibrationDevice::Activate() { |
| 15 | if (ref_counter == 0 && is_mounted) { | ||
| 16 | f32 volume = 1.0f; | ||
| 17 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 18 | if (result.IsSuccess()) { | ||
| 19 | xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE); | ||
| 20 | // TODO: SendNotificationPattern; | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 14 | ref_counter++; | 24 | ref_counter++; |
| 15 | return ResultSuccess; | 25 | return ResultSuccess; |
| 16 | } | 26 | } |
| 17 | 27 | ||
| 18 | Result NpadVibrationDevice::DecrementRefCounter() { | 28 | Result NpadVibrationDevice::Deactivate() { |
| 29 | if (ref_counter == 1 && is_mounted) { | ||
| 30 | f32 volume = 1.0f; | ||
| 31 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 32 | if (result.IsSuccess()) { | ||
| 33 | xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE); | ||
| 34 | // TODO: SendNotificationPattern; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 19 | if (ref_counter > 0) { | 38 | if (ref_counter > 0) { |
| 20 | ref_counter--; | 39 | ref_counter--; |
| 21 | } | 40 | } |
| @@ -23,6 +42,45 @@ Result NpadVibrationDevice::DecrementRefCounter() { | |||
| 23 | return ResultSuccess; | 42 | return ResultSuccess; |
| 24 | } | 43 | } |
| 25 | 44 | ||
| 45 | Result NpadVibrationDevice::Mount(IAbstractedPad& abstracted_pad, Core::HID::DeviceIndex index, | ||
| 46 | NpadVibration* handler) { | ||
| 47 | if (!abstracted_pad.internal_flags.is_connected) { | ||
| 48 | return ResultSuccess; | ||
| 49 | } | ||
| 50 | xcd_handle = abstracted_pad.xcd_handle; | ||
| 51 | device_index = index; | ||
| 52 | vibration_handler = handler; | ||
| 53 | is_mounted = true; | ||
| 54 | |||
| 55 | if (ref_counter == 0) { | ||
| 56 | return ResultSuccess; | ||
| 57 | } | ||
| 58 | |||
| 59 | f32 volume{1.0f}; | ||
| 60 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 61 | if (result.IsSuccess()) { | ||
| 62 | xcd_handle->SetVibration(false); | ||
| 63 | } | ||
| 64 | |||
| 65 | return ResultSuccess; | ||
| 66 | } | ||
| 67 | |||
| 68 | Result NpadVibrationDevice::Unmount() { | ||
| 69 | if (ref_counter == 0 || !is_mounted) { | ||
| 70 | is_mounted = false; | ||
| 71 | return ResultSuccess; | ||
| 72 | } | ||
| 73 | |||
| 74 | f32 volume{1.0f}; | ||
| 75 | const auto result = vibration_handler->GetVibrationVolume(volume); | ||
| 76 | if (result.IsSuccess()) { | ||
| 77 | xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE); | ||
| 78 | } | ||
| 79 | |||
| 80 | is_mounted = false; | ||
| 81 | return ResultSuccess; | ||
| 82 | } | ||
| 83 | |||
| 26 | Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& value) { | 84 | Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& value) { |
| 27 | if (ref_counter == 0) { | 85 | if (ref_counter == 0) { |
| 28 | return ResultVibrationNotInitialized; | 86 | return ResultVibrationNotInitialized; |
| @@ -37,7 +95,7 @@ Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& | |||
| 37 | return result; | 95 | return result; |
| 38 | } | 96 | } |
| 39 | if (volume <= 0.0f) { | 97 | if (volume <= 0.0f) { |
| 40 | // TODO: SendVibrationValue | 98 | xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE); |
| 41 | return ResultSuccess; | 99 | return ResultSuccess; |
| 42 | } | 100 | } |
| 43 | 101 | ||
| @@ -45,7 +103,7 @@ Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& | |||
| 45 | vibration_value.high_amplitude *= volume; | 103 | vibration_value.high_amplitude *= volume; |
| 46 | vibration_value.low_amplitude *= volume; | 104 | vibration_value.low_amplitude *= volume; |
| 47 | 105 | ||
| 48 | // TODO: SendVibrationValue | 106 | xcd_handle->SetVibration(device_index, vibration_value); |
| 49 | return ResultSuccess; | 107 | return ResultSuccess; |
| 50 | } | 108 | } |
| 51 | 109 | ||
| @@ -63,11 +121,11 @@ Result NpadVibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u3 | |||
| 63 | pattern = 0; | 121 | pattern = 0; |
| 64 | } | 122 | } |
| 65 | 123 | ||
| 66 | // return xcd_handle->SendVibrationNotificationPattern(pattern); | 124 | // TODO: SendVibrationNotificationPattern; |
| 67 | return ResultSuccess; | 125 | return ResultSuccess; |
| 68 | } | 126 | } |
| 69 | 127 | ||
| 70 | Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) { | 128 | Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) const { |
| 71 | if (ref_counter < 1) { | 129 | if (ref_counter < 1) { |
| 72 | return ResultVibrationNotInitialized; | 130 | return ResultVibrationNotInitialized; |
| 73 | } | 131 | } |
| @@ -77,7 +135,7 @@ Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& o | |||
| 77 | return ResultSuccess; | 135 | return ResultSuccess; |
| 78 | } | 136 | } |
| 79 | 137 | ||
| 80 | // TODO: SendVibrationValue | 138 | out_value = xcd_handle->GetActualVibrationValue(device_index); |
| 81 | return ResultSuccess; | 139 | return ResultSuccess; |
| 82 | } | 140 | } |
| 83 | 141 | ||
diff --git a/src/hid_core/resources/vibration/vibration_device.h b/src/hid_core/resources/vibration/vibration_device.h index 3574ad60b..c2f9891d3 100644 --- a/src/hid_core/resources/vibration/vibration_device.h +++ b/src/hid_core/resources/vibration/vibration_device.h | |||
| @@ -12,6 +12,10 @@ | |||
| 12 | #include "hid_core/resources/npad/npad_types.h" | 12 | #include "hid_core/resources/npad/npad_types.h" |
| 13 | #include "hid_core/resources/vibration/vibration_base.h" | 13 | #include "hid_core/resources/vibration/vibration_base.h" |
| 14 | 14 | ||
| 15 | namespace Core::HID { | ||
| 16 | enum class DeviceIndex : u8; | ||
| 17 | } | ||
| 18 | |||
| 15 | namespace Service::HID { | 19 | namespace Service::HID { |
| 16 | class NpadVibration; | 20 | class NpadVibration; |
| 17 | 21 | ||
| @@ -20,16 +24,20 @@ class NpadVibrationDevice final : public NpadVibrationBase { | |||
| 20 | public: | 24 | public: |
| 21 | explicit NpadVibrationDevice(); | 25 | explicit NpadVibrationDevice(); |
| 22 | 26 | ||
| 23 | Result IncrementRefCounter(); | 27 | Result Activate(); |
| 24 | Result DecrementRefCounter(); | 28 | Result Deactivate(); |
| 29 | |||
| 30 | Result Mount(IAbstractedPad& abstracted_pad, Core::HID::DeviceIndex index, | ||
| 31 | NpadVibration* handler); | ||
| 32 | Result Unmount(); | ||
| 25 | 33 | ||
| 26 | Result SendVibrationValue(const Core::HID::VibrationValue& value); | 34 | Result SendVibrationValue(const Core::HID::VibrationValue& value); |
| 27 | Result SendVibrationNotificationPattern(u32 pattern); | 35 | Result SendVibrationNotificationPattern(u32 pattern); |
| 28 | 36 | ||
| 29 | Result GetActualVibrationValue(Core::HID::VibrationValue& out_value); | 37 | Result GetActualVibrationValue(Core::HID::VibrationValue& out_value) const; |
| 30 | 38 | ||
| 31 | private: | 39 | private: |
| 32 | u32 device_index{}; | 40 | Core::HID::DeviceIndex device_index{}; |
| 33 | }; | 41 | }; |
| 34 | 42 | ||
| 35 | } // namespace Service::HID | 43 | } // namespace Service::HID |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index d2fbea488..d0a71a15b 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | # SPDX-License-Identifier: GPL-2.0-or-later | 2 | # SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | add_library(input_common STATIC | 4 | add_library(input_common STATIC |
| 5 | drivers/android.cpp | ||
| 6 | drivers/android.h | ||
| 5 | drivers/camera.cpp | 7 | drivers/camera.cpp |
| 6 | drivers/camera.h | 8 | drivers/camera.h |
| 7 | drivers/keyboard.cpp | 9 | drivers/keyboard.cpp |
diff --git a/src/input_common/drivers/android.cpp b/src/input_common/drivers/android.cpp new file mode 100644 index 000000000..b6a03fdc0 --- /dev/null +++ b/src/input_common/drivers/android.cpp | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #include "input_common/drivers/android.h" | ||
| 5 | |||
| 6 | namespace InputCommon { | ||
| 7 | |||
| 8 | Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {} | ||
| 9 | |||
| 10 | void Android::RegisterController(std::size_t controller_number) { | ||
| 11 | PreSetController(GetIdentifier(controller_number)); | ||
| 12 | } | ||
| 13 | |||
| 14 | void Android::SetButtonState(std::size_t controller_number, int button_id, bool value) { | ||
| 15 | const auto identifier = GetIdentifier(controller_number); | ||
| 16 | SetButton(identifier, button_id, value); | ||
| 17 | } | ||
| 18 | |||
| 19 | void Android::SetAxisState(std::size_t controller_number, int axis_id, float value) { | ||
| 20 | const auto identifier = GetIdentifier(controller_number); | ||
| 21 | SetAxis(identifier, axis_id, value); | ||
| 22 | } | ||
| 23 | |||
| 24 | void Android::SetMotionState(std::size_t controller_number, u64 delta_timestamp, float gyro_x, | ||
| 25 | float gyro_y, float gyro_z, float accel_x, float accel_y, | ||
| 26 | float accel_z) { | ||
| 27 | const auto identifier = GetIdentifier(controller_number); | ||
| 28 | const BasicMotion motion_data{ | ||
| 29 | .gyro_x = gyro_x, | ||
| 30 | .gyro_y = gyro_y, | ||
| 31 | .gyro_z = gyro_z, | ||
| 32 | .accel_x = accel_x, | ||
| 33 | .accel_y = accel_y, | ||
| 34 | .accel_z = accel_z, | ||
| 35 | .delta_timestamp = delta_timestamp, | ||
| 36 | }; | ||
| 37 | SetMotion(identifier, 0, motion_data); | ||
| 38 | } | ||
| 39 | |||
| 40 | PadIdentifier Android::GetIdentifier(std::size_t controller_number) const { | ||
| 41 | return { | ||
| 42 | .guid = Common::UUID{}, | ||
| 43 | .port = controller_number, | ||
| 44 | .pad = 0, | ||
| 45 | }; | ||
| 46 | } | ||
| 47 | |||
| 48 | } // namespace InputCommon | ||
diff --git a/src/input_common/drivers/android.h b/src/input_common/drivers/android.h new file mode 100644 index 000000000..3f01817f6 --- /dev/null +++ b/src/input_common/drivers/android.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include "input_common/input_engine.h" | ||
| 7 | |||
| 8 | namespace InputCommon { | ||
| 9 | |||
| 10 | /** | ||
| 11 | * A virtual controller that is always assigned to the game input | ||
| 12 | */ | ||
| 13 | class Android final : public InputEngine { | ||
| 14 | public: | ||
| 15 | explicit Android(std::string input_engine_); | ||
| 16 | |||
| 17 | /** | ||
| 18 | * Registers controller number to accept new inputs | ||
| 19 | * @param controller_number the controller number that will take this action | ||
| 20 | */ | ||
| 21 | void RegisterController(std::size_t controller_number); | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Sets the status of all buttons bound with the key to pressed | ||
| 25 | * @param controller_number the controller number that will take this action | ||
| 26 | * @param button_id the id of the button | ||
| 27 | * @param value indicates if the button is pressed or not | ||
| 28 | */ | ||
| 29 | void SetButtonState(std::size_t controller_number, int button_id, bool value); | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Sets the status of a analog input to a specific player index | ||
| 33 | * @param controller_number the controller number that will take this action | ||
| 34 | * @param axis_id the id of the axis to move | ||
| 35 | * @param value the analog position of the axis | ||
| 36 | */ | ||
| 37 | void SetAxisState(std::size_t controller_number, int axis_id, float value); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * Sets the status of the motion sensor to a specific player index | ||
| 41 | * @param controller_number the controller number that will take this action | ||
| 42 | * @param delta_timestamp time passed since last reading | ||
| 43 | * @param gyro_x,gyro_y,gyro_z the gyro sensor readings | ||
| 44 | * @param accel_x,accel_y,accel_z the accelerometer reading | ||
| 45 | */ | ||
| 46 | void SetMotionState(std::size_t controller_number, u64 delta_timestamp, float gyro_x, | ||
| 47 | float gyro_y, float gyro_z, float accel_x, float accel_y, float accel_z); | ||
| 48 | |||
| 49 | private: | ||
| 50 | /// Returns the correct identifier corresponding to the player index | ||
| 51 | PadIdentifier GetIdentifier(std::size_t controller_number) const; | ||
| 52 | }; | ||
| 53 | |||
| 54 | } // namespace InputCommon | ||
diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 8c2ee4eb3..f1a1d7398 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp | |||
| @@ -210,6 +210,9 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const { | |||
| 210 | if (data.engine == "analog_from_button") { | 210 | if (data.engine == "analog_from_button") { |
| 211 | return false; | 211 | return false; |
| 212 | } | 212 | } |
| 213 | if (data.engine == "virtual_gamepad") { | ||
| 214 | return false; | ||
| 215 | } | ||
| 213 | return true; | 216 | return true; |
| 214 | } | 217 | } |
| 215 | 218 | ||
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index c77fc04ee..f8749ebbf 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <memory> | 4 | #include <memory> |
| 5 | #include "common/input.h" | 5 | #include "common/input.h" |
| 6 | #include "common/param_package.h" | 6 | #include "common/param_package.h" |
| 7 | #include "input_common/drivers/android.h" | ||
| 7 | #include "input_common/drivers/camera.h" | 8 | #include "input_common/drivers/camera.h" |
| 8 | #include "input_common/drivers/keyboard.h" | 9 | #include "input_common/drivers/keyboard.h" |
| 9 | #include "input_common/drivers/mouse.h" | 10 | #include "input_common/drivers/mouse.h" |
| @@ -78,6 +79,7 @@ struct InputSubsystem::Impl { | |||
| 78 | RegisterEngine("cemuhookudp", udp_client); | 79 | RegisterEngine("cemuhookudp", udp_client); |
| 79 | RegisterEngine("tas", tas_input); | 80 | RegisterEngine("tas", tas_input); |
| 80 | RegisterEngine("camera", camera); | 81 | RegisterEngine("camera", camera); |
| 82 | RegisterEngine("android", android); | ||
| 81 | RegisterEngine("virtual_amiibo", virtual_amiibo); | 83 | RegisterEngine("virtual_amiibo", virtual_amiibo); |
| 82 | RegisterEngine("virtual_gamepad", virtual_gamepad); | 84 | RegisterEngine("virtual_gamepad", virtual_gamepad); |
| 83 | #ifdef HAVE_SDL2 | 85 | #ifdef HAVE_SDL2 |
| @@ -109,6 +111,7 @@ struct InputSubsystem::Impl { | |||
| 109 | UnregisterEngine(udp_client); | 111 | UnregisterEngine(udp_client); |
| 110 | UnregisterEngine(tas_input); | 112 | UnregisterEngine(tas_input); |
| 111 | UnregisterEngine(camera); | 113 | UnregisterEngine(camera); |
| 114 | UnregisterEngine(android); | ||
| 112 | UnregisterEngine(virtual_amiibo); | 115 | UnregisterEngine(virtual_amiibo); |
| 113 | UnregisterEngine(virtual_gamepad); | 116 | UnregisterEngine(virtual_gamepad); |
| 114 | #ifdef HAVE_SDL2 | 117 | #ifdef HAVE_SDL2 |
| @@ -129,6 +132,8 @@ struct InputSubsystem::Impl { | |||
| 129 | devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end()); | 132 | devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end()); |
| 130 | auto mouse_devices = mouse->GetInputDevices(); | 133 | auto mouse_devices = mouse->GetInputDevices(); |
| 131 | devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); | 134 | devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); |
| 135 | auto android_devices = android->GetInputDevices(); | ||
| 136 | devices.insert(devices.end(), android_devices.begin(), android_devices.end()); | ||
| 132 | #ifdef HAVE_LIBUSB | 137 | #ifdef HAVE_LIBUSB |
| 133 | auto gcadapter_devices = gcadapter->GetInputDevices(); | 138 | auto gcadapter_devices = gcadapter->GetInputDevices(); |
| 134 | devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); | 139 | devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); |
| @@ -157,6 +162,9 @@ struct InputSubsystem::Impl { | |||
| 157 | if (engine == mouse->GetEngineName()) { | 162 | if (engine == mouse->GetEngineName()) { |
| 158 | return mouse; | 163 | return mouse; |
| 159 | } | 164 | } |
| 165 | if (engine == android->GetEngineName()) { | ||
| 166 | return android; | ||
| 167 | } | ||
| 160 | #ifdef HAVE_LIBUSB | 168 | #ifdef HAVE_LIBUSB |
| 161 | if (engine == gcadapter->GetEngineName()) { | 169 | if (engine == gcadapter->GetEngineName()) { |
| 162 | return gcadapter; | 170 | return gcadapter; |
| @@ -237,6 +245,9 @@ struct InputSubsystem::Impl { | |||
| 237 | if (engine == mouse->GetEngineName()) { | 245 | if (engine == mouse->GetEngineName()) { |
| 238 | return true; | 246 | return true; |
| 239 | } | 247 | } |
| 248 | if (engine == android->GetEngineName()) { | ||
| 249 | return true; | ||
| 250 | } | ||
| 240 | #ifdef HAVE_LIBUSB | 251 | #ifdef HAVE_LIBUSB |
| 241 | if (engine == gcadapter->GetEngineName()) { | 252 | if (engine == gcadapter->GetEngineName()) { |
| 242 | return true; | 253 | return true; |
| @@ -265,6 +276,7 @@ struct InputSubsystem::Impl { | |||
| 265 | void BeginConfiguration() { | 276 | void BeginConfiguration() { |
| 266 | keyboard->BeginConfiguration(); | 277 | keyboard->BeginConfiguration(); |
| 267 | mouse->BeginConfiguration(); | 278 | mouse->BeginConfiguration(); |
| 279 | android->BeginConfiguration(); | ||
| 268 | #ifdef HAVE_LIBUSB | 280 | #ifdef HAVE_LIBUSB |
| 269 | gcadapter->BeginConfiguration(); | 281 | gcadapter->BeginConfiguration(); |
| 270 | #endif | 282 | #endif |
| @@ -278,6 +290,7 @@ struct InputSubsystem::Impl { | |||
| 278 | void EndConfiguration() { | 290 | void EndConfiguration() { |
| 279 | keyboard->EndConfiguration(); | 291 | keyboard->EndConfiguration(); |
| 280 | mouse->EndConfiguration(); | 292 | mouse->EndConfiguration(); |
| 293 | android->EndConfiguration(); | ||
| 281 | #ifdef HAVE_LIBUSB | 294 | #ifdef HAVE_LIBUSB |
| 282 | gcadapter->EndConfiguration(); | 295 | gcadapter->EndConfiguration(); |
| 283 | #endif | 296 | #endif |
| @@ -308,6 +321,7 @@ struct InputSubsystem::Impl { | |||
| 308 | std::shared_ptr<TasInput::Tas> tas_input; | 321 | std::shared_ptr<TasInput::Tas> tas_input; |
| 309 | std::shared_ptr<CemuhookUDP::UDPClient> udp_client; | 322 | std::shared_ptr<CemuhookUDP::UDPClient> udp_client; |
| 310 | std::shared_ptr<Camera> camera; | 323 | std::shared_ptr<Camera> camera; |
| 324 | std::shared_ptr<Android> android; | ||
| 311 | std::shared_ptr<VirtualAmiibo> virtual_amiibo; | 325 | std::shared_ptr<VirtualAmiibo> virtual_amiibo; |
| 312 | std::shared_ptr<VirtualGamepad> virtual_gamepad; | 326 | std::shared_ptr<VirtualGamepad> virtual_gamepad; |
| 313 | 327 | ||
| @@ -373,6 +387,14 @@ const Camera* InputSubsystem::GetCamera() const { | |||
| 373 | return impl->camera.get(); | 387 | return impl->camera.get(); |
| 374 | } | 388 | } |
| 375 | 389 | ||
| 390 | Android* InputSubsystem::GetAndroid() { | ||
| 391 | return impl->android.get(); | ||
| 392 | } | ||
| 393 | |||
| 394 | const Android* InputSubsystem::GetAndroid() const { | ||
| 395 | return impl->android.get(); | ||
| 396 | } | ||
| 397 | |||
| 376 | VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() { | 398 | VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() { |
| 377 | return impl->virtual_amiibo.get(); | 399 | return impl->virtual_amiibo.get(); |
| 378 | } | 400 | } |
diff --git a/src/input_common/main.h b/src/input_common/main.h index d64a6cb4c..1d19019ee 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h | |||
| @@ -29,6 +29,7 @@ enum Values : int; | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | namespace InputCommon { | 31 | namespace InputCommon { |
| 32 | class Android; | ||
| 32 | class Camera; | 33 | class Camera; |
| 33 | class Keyboard; | 34 | class Keyboard; |
| 34 | class Mouse; | 35 | class Mouse; |
| @@ -103,6 +104,12 @@ public: | |||
| 103 | /// Retrieves the underlying camera input device. | 104 | /// Retrieves the underlying camera input device. |
| 104 | [[nodiscard]] const Camera* GetCamera() const; | 105 | [[nodiscard]] const Camera* GetCamera() const; |
| 105 | 106 | ||
| 107 | /// Retrieves the underlying android input device. | ||
| 108 | [[nodiscard]] Android* GetAndroid(); | ||
| 109 | |||
| 110 | /// Retrieves the underlying android input device. | ||
| 111 | [[nodiscard]] const Android* GetAndroid() const; | ||
| 112 | |||
| 106 | /// Retrieves the underlying virtual amiibo input device. | 113 | /// Retrieves the underlying virtual amiibo input device. |
| 107 | [[nodiscard]] VirtualAmiibo* GetVirtualAmiibo(); | 114 | [[nodiscard]] VirtualAmiibo* GetVirtualAmiibo(); |
| 108 | 115 | ||
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 800754554..64a4e0e55 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |||
| @@ -12,6 +12,11 @@ namespace Shader::Backend::SPIRV { | |||
| 12 | namespace { | 12 | namespace { |
| 13 | class ImageOperands { | 13 | class ImageOperands { |
| 14 | public: | 14 | public: |
| 15 | [[maybe_unused]] static constexpr bool ImageSampleOffsetAllowed = false; | ||
| 16 | [[maybe_unused]] static constexpr bool ImageGatherOffsetAllowed = true; | ||
| 17 | [[maybe_unused]] static constexpr bool ImageFetchOffsetAllowed = false; | ||
| 18 | [[maybe_unused]] static constexpr bool ImageGradientOffsetAllowed = false; | ||
| 19 | |||
| 15 | explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp, | 20 | explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp, |
| 16 | Id lod, const IR::Value& offset) { | 21 | Id lod, const IR::Value& offset) { |
| 17 | if (has_bias) { | 22 | if (has_bias) { |
| @@ -22,7 +27,7 @@ public: | |||
| 22 | const Id lod_value{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod}; | 27 | const Id lod_value{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod}; |
| 23 | Add(spv::ImageOperandsMask::Lod, lod_value); | 28 | Add(spv::ImageOperandsMask::Lod, lod_value); |
| 24 | } | 29 | } |
| 25 | AddOffset(ctx, offset); | 30 | AddOffset(ctx, offset, ImageSampleOffsetAllowed); |
| 26 | if (has_lod_clamp) { | 31 | if (has_lod_clamp) { |
| 27 | const Id lod_clamp{has_bias ? ctx.OpCompositeExtract(ctx.F32[1], lod, 1) : lod}; | 32 | const Id lod_clamp{has_bias ? ctx.OpCompositeExtract(ctx.F32[1], lod, 1) : lod}; |
| 28 | Add(spv::ImageOperandsMask::MinLod, lod_clamp); | 33 | Add(spv::ImageOperandsMask::MinLod, lod_clamp); |
| @@ -55,20 +60,17 @@ public: | |||
| 55 | Add(spv::ImageOperandsMask::ConstOffsets, offsets); | 60 | Add(spv::ImageOperandsMask::ConstOffsets, offsets); |
| 56 | } | 61 | } |
| 57 | 62 | ||
| 58 | explicit ImageOperands(Id offset, Id lod, Id ms) { | 63 | explicit ImageOperands(Id lod, Id ms) { |
| 59 | if (Sirit::ValidId(lod)) { | 64 | if (Sirit::ValidId(lod)) { |
| 60 | Add(spv::ImageOperandsMask::Lod, lod); | 65 | Add(spv::ImageOperandsMask::Lod, lod); |
| 61 | } | 66 | } |
| 62 | if (Sirit::ValidId(offset)) { | ||
| 63 | Add(spv::ImageOperandsMask::Offset, offset); | ||
| 64 | } | ||
| 65 | if (Sirit::ValidId(ms)) { | 67 | if (Sirit::ValidId(ms)) { |
| 66 | Add(spv::ImageOperandsMask::Sample, ms); | 68 | Add(spv::ImageOperandsMask::Sample, ms); |
| 67 | } | 69 | } |
| 68 | } | 70 | } |
| 69 | 71 | ||
| 70 | explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives, | 72 | explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives, |
| 71 | u32 num_derivatives, Id offset, Id lod_clamp) { | 73 | u32 num_derivatives, const IR::Value& offset, Id lod_clamp) { |
| 72 | if (!Sirit::ValidId(derivatives)) { | 74 | if (!Sirit::ValidId(derivatives)) { |
| 73 | throw LogicError("Derivatives must be present"); | 75 | throw LogicError("Derivatives must be present"); |
| 74 | } | 76 | } |
| @@ -83,16 +85,14 @@ public: | |||
| 83 | const Id derivatives_Y{ctx.OpCompositeConstruct( | 85 | const Id derivatives_Y{ctx.OpCompositeConstruct( |
| 84 | ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})}; | 86 | ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})}; |
| 85 | Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y); | 87 | Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y); |
| 86 | if (Sirit::ValidId(offset)) { | 88 | AddOffset(ctx, offset, ImageGradientOffsetAllowed); |
| 87 | Add(spv::ImageOperandsMask::Offset, offset); | ||
| 88 | } | ||
| 89 | if (has_lod_clamp) { | 89 | if (has_lod_clamp) { |
| 90 | Add(spv::ImageOperandsMask::MinLod, lod_clamp); | 90 | Add(spv::ImageOperandsMask::MinLod, lod_clamp); |
| 91 | } | 91 | } |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2, | 94 | explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2, |
| 95 | Id offset, Id lod_clamp) { | 95 | const IR::Value& offset, Id lod_clamp) { |
| 96 | if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) { | 96 | if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) { |
| 97 | throw LogicError("Derivatives must be present"); | 97 | throw LogicError("Derivatives must be present"); |
| 98 | } | 98 | } |
| @@ -111,9 +111,7 @@ public: | |||
| 111 | const Id derivatives_id2{ctx.OpCompositeConstruct( | 111 | const Id derivatives_id2{ctx.OpCompositeConstruct( |
| 112 | ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})}; | 112 | ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})}; |
| 113 | Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2); | 113 | Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2); |
| 114 | if (Sirit::ValidId(offset)) { | 114 | AddOffset(ctx, offset, ImageGradientOffsetAllowed); |
| 115 | Add(spv::ImageOperandsMask::Offset, offset); | ||
| 116 | } | ||
| 117 | if (has_lod_clamp) { | 115 | if (has_lod_clamp) { |
| 118 | Add(spv::ImageOperandsMask::MinLod, lod_clamp); | 116 | Add(spv::ImageOperandsMask::MinLod, lod_clamp); |
| 119 | } | 117 | } |
| @@ -132,7 +130,7 @@ public: | |||
| 132 | } | 130 | } |
| 133 | 131 | ||
| 134 | private: | 132 | private: |
| 135 | void AddOffset(EmitContext& ctx, const IR::Value& offset) { | 133 | void AddOffset(EmitContext& ctx, const IR::Value& offset, bool runtime_offset_allowed) { |
| 136 | if (offset.IsEmpty()) { | 134 | if (offset.IsEmpty()) { |
| 137 | return; | 135 | return; |
| 138 | } | 136 | } |
| @@ -165,7 +163,9 @@ private: | |||
| 165 | break; | 163 | break; |
| 166 | } | 164 | } |
| 167 | } | 165 | } |
| 168 | Add(spv::ImageOperandsMask::Offset, ctx.Def(offset)); | 166 | if (runtime_offset_allowed) { |
| 167 | Add(spv::ImageOperandsMask::Offset, ctx.Def(offset)); | ||
| 168 | } | ||
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | void Add(spv::ImageOperandsMask new_mask, Id value) { | 171 | void Add(spv::ImageOperandsMask new_mask, Id value) { |
| @@ -311,6 +311,37 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info, | |||
| 311 | return coords; | 311 | return coords; |
| 312 | } | 312 | } |
| 313 | } | 313 | } |
| 314 | |||
| 315 | void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, Id& coords, | ||
| 316 | Id offset) { | ||
| 317 | if (!Sirit::ValidId(offset)) { | ||
| 318 | return; | ||
| 319 | } | ||
| 320 | |||
| 321 | Id result_type{}; | ||
| 322 | switch (info.type) { | ||
| 323 | case TextureType::Buffer: | ||
| 324 | case TextureType::Color1D: | ||
| 325 | case TextureType::ColorArray1D: { | ||
| 326 | result_type = ctx.U32[1]; | ||
| 327 | break; | ||
| 328 | } | ||
| 329 | case TextureType::Color2D: | ||
| 330 | case TextureType::Color2DRect: | ||
| 331 | case TextureType::ColorArray2D: { | ||
| 332 | result_type = ctx.U32[2]; | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | case TextureType::Color3D: { | ||
| 336 | result_type = ctx.U32[3]; | ||
| 337 | break; | ||
| 338 | } | ||
| 339 | case TextureType::ColorCube: | ||
| 340 | case TextureType::ColorArrayCube: | ||
| 341 | return; | ||
| 342 | } | ||
| 343 | coords = ctx.OpIAdd(result_type, coords, offset); | ||
| 344 | } | ||
| 314 | } // Anonymous namespace | 345 | } // Anonymous namespace |
| 315 | 346 | ||
| 316 | Id EmitBindlessImageSampleImplicitLod(EmitContext&) { | 347 | Id EmitBindlessImageSampleImplicitLod(EmitContext&) { |
| @@ -496,6 +527,7 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, | |||
| 496 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, | 527 | Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset, |
| 497 | Id lod, Id ms) { | 528 | Id lod, Id ms) { |
| 498 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 529 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 530 | AddOffsetToCoordinates(ctx, info, coords, offset); | ||
| 499 | if (info.type == TextureType::Buffer) { | 531 | if (info.type == TextureType::Buffer) { |
| 500 | lod = Id{}; | 532 | lod = Id{}; |
| 501 | } | 533 | } |
| @@ -503,7 +535,7 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c | |||
| 503 | // This image is multisampled, lod must be implicit | 535 | // This image is multisampled, lod must be implicit |
| 504 | lod = Id{}; | 536 | lod = Id{}; |
| 505 | } | 537 | } |
| 506 | const ImageOperands operands(offset, lod, ms); | 538 | const ImageOperands operands(lod, ms); |
| 507 | return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], | 539 | return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4], |
| 508 | TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); | 540 | TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span()); |
| 509 | } | 541 | } |
| @@ -548,13 +580,13 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I | |||
| 548 | } | 580 | } |
| 549 | 581 | ||
| 550 | Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 582 | Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 551 | Id derivatives, Id offset, Id lod_clamp) { | 583 | Id derivatives, const IR::Value& offset, Id lod_clamp) { |
| 552 | const auto info{inst->Flags<IR::TextureInstInfo>()}; | 584 | const auto info{inst->Flags<IR::TextureInstInfo>()}; |
| 553 | const auto operands = | 585 | const auto operands = info.num_derivatives == 3 |
| 554 | info.num_derivatives == 3 | 586 | ? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, |
| 555 | ? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, offset, {}, lod_clamp) | 587 | ctx.Def(offset), {}, lod_clamp) |
| 556 | : ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives, offset, | 588 | : ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, |
| 557 | lod_clamp); | 589 | info.num_derivatives, offset, lod_clamp); |
| 558 | return Emit(&EmitContext::OpImageSparseSampleExplicitLod, | 590 | return Emit(&EmitContext::OpImageSparseSampleExplicitLod, |
| 559 | &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], | 591 | &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], |
| 560 | Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); | 592 | Texture(ctx, info, index), coords, operands.Mask(), operands.Span()); |
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 7d34575c8..5c01b1012 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h | |||
| @@ -543,7 +543,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i | |||
| 543 | const IR::Value& skip_mips); | 543 | const IR::Value& skip_mips); |
| 544 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); | 544 | Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); |
| 545 | Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, | 545 | Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, |
| 546 | Id derivatives, Id offset, Id lod_clamp); | 546 | Id derivatives, const IR::Value& offset, Id lod_clamp); |
| 547 | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); | 547 | Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); |
| 548 | void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); | 548 | void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); |
| 549 | Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index); | 549 | Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index); |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 90278052a..93b03b917 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -351,7 +351,7 @@ if (APPLE) | |||
| 351 | 351 | ||
| 352 | if (NOT USE_SYSTEM_MOLTENVK) | 352 | if (NOT USE_SYSTEM_MOLTENVK) |
| 353 | set(MOLTENVK_PLATFORM "macOS") | 353 | set(MOLTENVK_PLATFORM "macOS") |
| 354 | set(MOLTENVK_VERSION "v1.2.5") | 354 | set(MOLTENVK_VERSION "v1.2.7") |
| 355 | download_moltenvk_external(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION}) | 355 | download_moltenvk_external(${MOLTENVK_PLATFORM} ${MOLTENVK_VERSION}) |
| 356 | endif() | 356 | endif() |
| 357 | find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED) | 357 | find_library(MOLTENVK_LIBRARY MoltenVK REQUIRED) |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 5dac9f1e7..400917f9d 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -1650,9 +1650,21 @@ void ConfigureInputPlayer::SaveProfile() { | |||
| 1650 | void ConfigureInputPlayer::UpdateInputProfiles() { | 1650 | void ConfigureInputPlayer::UpdateInputProfiles() { |
| 1651 | ui->comboProfiles->clear(); | 1651 | ui->comboProfiles->clear(); |
| 1652 | 1652 | ||
| 1653 | for (const auto& profile_name : profiles->GetInputProfileNames()) { | 1653 | // Set current profile as empty by default |
| 1654 | int profile_index = -1; | ||
| 1655 | |||
| 1656 | // Add every available profile and search the player profile to set it as current one | ||
| 1657 | auto& current_profile = Settings::values.players.GetValue()[player_index].profile_name; | ||
| 1658 | std::vector<std::string> profile_names = profiles->GetInputProfileNames(); | ||
| 1659 | std::string profile_name; | ||
| 1660 | for (size_t i = 0; i < profile_names.size(); i++) { | ||
| 1661 | profile_name = profile_names[i]; | ||
| 1654 | ui->comboProfiles->addItem(QString::fromStdString(profile_name)); | 1662 | ui->comboProfiles->addItem(QString::fromStdString(profile_name)); |
| 1663 | if (current_profile == profile_name) { | ||
| 1664 | profile_index = (int)i; | ||
| 1665 | } | ||
| 1655 | } | 1666 | } |
| 1656 | 1667 | ||
| 1657 | ui->comboProfiles->setCurrentIndex(-1); | 1668 | LOG_DEBUG(Frontend, "Setting the current input profile to index {}", profile_index); |
| 1669 | ui->comboProfiles->setCurrentIndex(profile_index); | ||
| 1658 | } | 1670 | } |
diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index 140a7fe5d..568775027 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp | |||
| @@ -122,9 +122,8 @@ void ConfigurePerGameAddons::LoadConfiguration() { | |||
| 122 | 122 | ||
| 123 | const auto& disabled = Settings::values.disabled_addons[title_id]; | 123 | const auto& disabled = Settings::values.disabled_addons[title_id]; |
| 124 | 124 | ||
| 125 | for (const auto& patch : pm.GetPatchVersionNames(update_raw)) { | 125 | for (const auto& patch : pm.GetPatches(update_raw)) { |
| 126 | const auto name = | 126 | const auto name = QString::fromStdString(patch.name); |
| 127 | QString::fromStdString(patch.first).replace(QStringLiteral("[D] "), QString{}); | ||
| 128 | 127 | ||
| 129 | auto* const first_item = new QStandardItem; | 128 | auto* const first_item = new QStandardItem; |
| 130 | first_item->setText(name); | 129 | first_item->setText(name); |
| @@ -136,7 +135,7 @@ void ConfigurePerGameAddons::LoadConfiguration() { | |||
| 136 | first_item->setCheckState(patch_disabled ? Qt::Unchecked : Qt::Checked); | 135 | first_item->setCheckState(patch_disabled ? Qt::Unchecked : Qt::Checked); |
| 137 | 136 | ||
| 138 | list_items.push_back(QList<QStandardItem*>{ | 137 | list_items.push_back(QList<QStandardItem*>{ |
| 139 | first_item, new QStandardItem{QString::fromStdString(patch.second)}}); | 138 | first_item, new QStandardItem{QString::fromStdString(patch.version)}}); |
| 140 | item_model->appendRow(list_items.back()); | 139 | item_model->appendRow(list_items.back()); |
| 141 | } | 140 | } |
| 142 | 141 | ||
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp index d898d8acc..6b1f4527b 100644 --- a/src/yuzu/configuration/configure_vibration.cpp +++ b/src/yuzu/configuration/configure_vibration.cpp | |||
| @@ -116,8 +116,8 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type | |||
| 116 | .high_amplitude = 1.0f, | 116 | .high_amplitude = 1.0f, |
| 117 | .high_frequency = 320.0f, | 117 | .high_frequency = 320.0f, |
| 118 | }; | 118 | }; |
| 119 | controller->SetVibration(0, vibration); | 119 | controller->SetVibration(Core::HID::DeviceIndex::Left, vibration); |
| 120 | controller->SetVibration(1, vibration); | 120 | controller->SetVibration(Core::HID::DeviceIndex::Right, vibration); |
| 121 | 121 | ||
| 122 | // Restore previous values | 122 | // Restore previous values |
| 123 | player.vibration_enabled = old_vibration_enabled; | 123 | player.vibration_enabled = old_vibration_enabled; |
| @@ -127,7 +127,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type | |||
| 127 | void ConfigureVibration::StopVibrations() { | 127 | void ConfigureVibration::StopVibrations() { |
| 128 | for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { | 128 | for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { |
| 129 | auto controller = hid_core.GetEmulatedControllerByIndex(i); | 129 | auto controller = hid_core.GetEmulatedControllerByIndex(i); |
| 130 | controller->SetVibration(0, Core::HID::DEFAULT_VIBRATION_VALUE); | 130 | controller->SetVibration(Core::HID::DeviceIndex::Left, Core::HID::DEFAULT_VIBRATION_VALUE); |
| 131 | controller->SetVibration(1, Core::HID::DEFAULT_VIBRATION_VALUE); | 131 | controller->SetVibration(Core::HID::DeviceIndex::Right, Core::HID::DEFAULT_VIBRATION_VALUE); |
| 132 | } | 132 | } |
| 133 | } | 133 | } |
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp index 716efbccd..ebebadc94 100644 --- a/src/yuzu/configuration/input_profiles.cpp +++ b/src/yuzu/configuration/input_profiles.cpp | |||
| @@ -5,6 +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 "common/logging/log.h" | ||
| 8 | #include "frontend_common/config.h" | 9 | #include "frontend_common/config.h" |
| 9 | #include "yuzu/configuration/input_profiles.h" | 10 | #include "yuzu/configuration/input_profiles.h" |
| 10 | 11 | ||
| @@ -113,6 +114,8 @@ bool InputProfiles::LoadProfile(const std::string& profile_name, std::size_t pla | |||
| 113 | return false; | 114 | return false; |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 117 | LOG_INFO(Config, "Loading input profile `{}`", profile_name); | ||
| 118 | |||
| 116 | map_profiles[profile_name]->ReadQtControlPlayerValues(player_index); | 119 | map_profiles[profile_name]->ReadQtControlPlayerValues(player_index); |
| 117 | return true; | 120 | return true; |
| 118 | } | 121 | } |
diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp index 6aca71d7c..1051031f2 100644 --- a/src/yuzu/configuration/qt_config.cpp +++ b/src/yuzu/configuration/qt_config.cpp | |||
| @@ -1,6 +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 "common/logging/log.h" | ||
| 4 | #include "input_common/main.h" | 5 | #include "input_common/main.h" |
| 5 | #include "qt_config.h" | 6 | #include "qt_config.h" |
| 6 | #include "uisettings.h" | 7 | #include "uisettings.h" |
| @@ -65,7 +66,7 @@ void QtConfig::ReloadAllValues() { | |||
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | void QtConfig::SaveAllValues() { | 68 | void QtConfig::SaveAllValues() { |
| 68 | Save(); | 69 | SaveValues(); |
| 69 | SaveQtValues(); | 70 | SaveQtValues(); |
| 70 | } | 71 | } |
| 71 | 72 | ||
| @@ -327,7 +328,10 @@ void QtConfig::ReadMultiplayerValues() { | |||
| 327 | 328 | ||
| 328 | void QtConfig::SaveQtValues() { | 329 | void QtConfig::SaveQtValues() { |
| 329 | if (global) { | 330 | if (global) { |
| 331 | LOG_DEBUG(Config, "Saving global Qt configuration values"); | ||
| 330 | SaveUIValues(); | 332 | SaveUIValues(); |
| 333 | } else { | ||
| 334 | LOG_DEBUG(Config, "Saving Qt configuration values"); | ||
| 331 | } | 335 | } |
| 332 | SaveQtControlValues(); | 336 | SaveQtControlValues(); |
| 333 | 337 | ||
| @@ -545,6 +549,7 @@ void QtConfig::ReadQtControlPlayerValues(std::size_t player_index) { | |||
| 545 | void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) { | 549 | void QtConfig::SaveQtControlPlayerValues(std::size_t player_index) { |
| 546 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); | 550 | BeginGroup(Settings::TranslateCategory(Settings::Category::Controls)); |
| 547 | 551 | ||
| 552 | LOG_DEBUG(Config, "Saving players control configuration values"); | ||
| 548 | SavePlayerValues(player_index); | 553 | SavePlayerValues(player_index); |
| 549 | SaveQtPlayerValues(player_index); | 554 | SaveQtPlayerValues(player_index); |
| 550 | 555 | ||
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index dc006832e..9747e3fb3 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp | |||
| @@ -164,18 +164,19 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager, | |||
| 164 | QString out; | 164 | QString out; |
| 165 | FileSys::VirtualFile update_raw; | 165 | FileSys::VirtualFile update_raw; |
| 166 | loader.ReadUpdateRaw(update_raw); | 166 | loader.ReadUpdateRaw(update_raw); |
| 167 | for (const auto& kv : patch_manager.GetPatchVersionNames(update_raw)) { | 167 | for (const auto& patch : patch_manager.GetPatches(update_raw)) { |
| 168 | const bool is_update = kv.first == "Update" || kv.first == "[D] Update"; | 168 | const bool is_update = patch.name == "Update"; |
| 169 | if (!updatable && is_update) { | 169 | if (!updatable && is_update) { |
| 170 | continue; | 170 | continue; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | const QString type = QString::fromStdString(kv.first); | 173 | const QString type = |
| 174 | QString::fromStdString(patch.enabled ? patch.name : "[D] " + patch.name); | ||
| 174 | 175 | ||
| 175 | if (kv.second.empty()) { | 176 | if (patch.version.empty()) { |
| 176 | out.append(QStringLiteral("%1\n").arg(type)); | 177 | out.append(QStringLiteral("%1\n").arg(type)); |
| 177 | } else { | 178 | } else { |
| 178 | auto ver = kv.second; | 179 | auto ver = patch.version; |
| 179 | 180 | ||
| 180 | // Display container name for packed updates | 181 | // Display container name for packed updates |
| 181 | if (is_update && ver == "PACKED") { | 182 | if (is_update && ver == "PACKED") { |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 33756febf..05bd4174c 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include "core/hle/service/am/applet_oe.h" | 47 | #include "core/hle/service/am/applet_oe.h" |
| 48 | #include "core/hle/service/am/applets/applets.h" | 48 | #include "core/hle/service/am/applets/applets.h" |
| 49 | #include "core/hle/service/set/system_settings_server.h" | 49 | #include "core/hle/service/set/system_settings_server.h" |
| 50 | #include "frontend_common/content_manager.h" | ||
| 50 | #include "hid_core/frontend/emulated_controller.h" | 51 | #include "hid_core/frontend/emulated_controller.h" |
| 51 | #include "hid_core/hid_core.h" | 52 | #include "hid_core/hid_core.h" |
| 52 | #include "yuzu/multiplayer/state.h" | 53 | #include "yuzu/multiplayer/state.h" |
| @@ -518,12 +519,21 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk | |||
| 518 | continue; | 519 | continue; |
| 519 | } | 520 | } |
| 520 | 521 | ||
| 522 | int user_arg_idx = ++i; | ||
| 521 | bool argument_ok; | 523 | bool argument_ok; |
| 522 | const std::size_t selected_user = args[++i].toUInt(&argument_ok); | 524 | std::size_t selected_user = args[user_arg_idx].toUInt(&argument_ok); |
| 523 | 525 | ||
| 524 | if (!argument_ok) { | 526 | if (!argument_ok) { |
| 525 | LOG_ERROR(Frontend, "Invalid user argument"); | 527 | // try to look it up by username, only finds the first username that matches. |
| 526 | continue; | 528 | const std::string user_arg_str = args[user_arg_idx].toStdString(); |
| 529 | const auto user_idx = system->GetProfileManager().GetUserIndex(user_arg_str); | ||
| 530 | |||
| 531 | if (user_idx == std::nullopt) { | ||
| 532 | LOG_ERROR(Frontend, "Invalid user argument"); | ||
| 533 | continue; | ||
| 534 | } | ||
| 535 | |||
| 536 | selected_user = user_idx.value(); | ||
| 527 | } | 537 | } |
| 528 | 538 | ||
| 529 | if (!system->GetProfileManager().UserExistsIndex(selected_user)) { | 539 | if (!system->GetProfileManager().UserExistsIndex(selected_user)) { |
| @@ -532,6 +542,8 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk | |||
| 532 | } | 542 | } |
| 533 | 543 | ||
| 534 | Settings::values.current_user = static_cast<s32>(selected_user); | 544 | Settings::values.current_user = static_cast<s32>(selected_user); |
| 545 | |||
| 546 | user_flag_cmd_line = true; | ||
| 535 | continue; | 547 | continue; |
| 536 | } | 548 | } |
| 537 | 549 | ||
| @@ -1942,7 +1954,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1942 | 1954 | ||
| 1943 | Settings::LogSettings(); | 1955 | Settings::LogSettings(); |
| 1944 | 1956 | ||
| 1945 | if (UISettings::values.select_user_on_boot) { | 1957 | if (UISettings::values.select_user_on_boot && !user_flag_cmd_line) { |
| 1946 | const Core::Frontend::ProfileSelectParameters parameters{ | 1958 | const Core::Frontend::ProfileSelectParameters parameters{ |
| 1947 | .mode = Service::AM::Applets::UiMode::UserSelector, | 1959 | .mode = Service::AM::Applets::UiMode::UserSelector, |
| 1948 | .invalid_uid_list = {}, | 1960 | .invalid_uid_list = {}, |
| @@ -1954,6 +1966,11 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t | |||
| 1954 | } | 1966 | } |
| 1955 | } | 1967 | } |
| 1956 | 1968 | ||
| 1969 | // If the user specifies -u (successfully) on the cmd line, don't prompt for a user on first | ||
| 1970 | // game startup only. If the user stops emulation and starts a new one, go back to the expected | ||
| 1971 | // behavior of asking. | ||
| 1972 | user_flag_cmd_line = false; | ||
| 1973 | |||
| 1957 | if (!LoadROM(filename, program_id, program_index, launch_type)) { | 1974 | if (!LoadROM(filename, program_id, program_index, launch_type)) { |
| 1958 | return; | 1975 | return; |
| 1959 | } | 1976 | } |
| @@ -2460,10 +2477,8 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT | |||
| 2460 | } | 2477 | } |
| 2461 | 2478 | ||
| 2462 | void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { | 2479 | void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { |
| 2463 | const auto& fs_controller = system->GetFileSystemController(); | 2480 | const auto res = |
| 2464 | const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) || | 2481 | ContentManager::RemoveBaseContent(system->GetFileSystemController(), program_id); |
| 2465 | fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id); | ||
| 2466 | |||
| 2467 | if (res) { | 2482 | if (res) { |
| 2468 | QMessageBox::information(this, tr("Successfully Removed"), | 2483 | QMessageBox::information(this, tr("Successfully Removed"), |
| 2469 | tr("Successfully removed the installed base game.")); | 2484 | tr("Successfully removed the installed base game.")); |
| @@ -2475,11 +2490,7 @@ void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { | |||
| 2475 | } | 2490 | } |
| 2476 | 2491 | ||
| 2477 | void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { | 2492 | void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { |
| 2478 | const auto update_id = program_id | 0x800; | 2493 | const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); |
| 2479 | const auto& fs_controller = system->GetFileSystemController(); | ||
| 2480 | const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) || | ||
| 2481 | fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id); | ||
| 2482 | |||
| 2483 | if (res) { | 2494 | if (res) { |
| 2484 | QMessageBox::information(this, tr("Successfully Removed"), | 2495 | QMessageBox::information(this, tr("Successfully Removed"), |
| 2485 | tr("Successfully removed the installed update.")); | 2496 | tr("Successfully removed the installed update.")); |
| @@ -2490,22 +2501,7 @@ void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { | |||
| 2490 | } | 2501 | } |
| 2491 | 2502 | ||
| 2492 | void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { | 2503 | void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { |
| 2493 | u32 count{}; | 2504 | const size_t count = ContentManager::RemoveAllDLC(system.get(), program_id); |
| 2494 | const auto& fs_controller = system->GetFileSystemController(); | ||
| 2495 | const auto dlc_entries = system->GetContentProvider().ListEntriesFilter( | ||
| 2496 | FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); | ||
| 2497 | |||
| 2498 | for (const auto& entry : dlc_entries) { | ||
| 2499 | if (FileSys::GetBaseTitleID(entry.title_id) == program_id) { | ||
| 2500 | const auto res = | ||
| 2501 | fs_controller.GetUserNANDContents()->RemoveExistingEntry(entry.title_id) || | ||
| 2502 | fs_controller.GetSDMCContents()->RemoveExistingEntry(entry.title_id); | ||
| 2503 | if (res) { | ||
| 2504 | ++count; | ||
| 2505 | } | ||
| 2506 | } | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | if (count == 0) { | 2505 | if (count == 0) { |
| 2510 | QMessageBox::warning(this, GetGameListErrorRemoving(type), | 2506 | QMessageBox::warning(this, GetGameListErrorRemoving(type), |
| 2511 | tr("There are no DLC installed for this title.")); | 2507 | tr("There are no DLC installed for this title.")); |
| @@ -3274,12 +3270,21 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 3274 | install_progress->setLabelText( | 3270 | install_progress->setLabelText( |
| 3275 | tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName())); | 3271 | tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName())); |
| 3276 | 3272 | ||
| 3277 | QFuture<InstallResult> future; | 3273 | QFuture<ContentManager::InstallResult> future; |
| 3278 | InstallResult result; | 3274 | ContentManager::InstallResult result; |
| 3279 | 3275 | ||
| 3280 | if (file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { | 3276 | if (file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { |
| 3281 | 3277 | const auto progress_callback = [this](size_t size, size_t progress) { | |
| 3282 | future = QtConcurrent::run([this, &file] { return InstallNSP(file); }); | 3278 | emit UpdateInstallProgress(); |
| 3279 | if (install_progress->wasCanceled()) { | ||
| 3280 | return true; | ||
| 3281 | } | ||
| 3282 | return false; | ||
| 3283 | }; | ||
| 3284 | future = QtConcurrent::run([this, &file, progress_callback] { | ||
| 3285 | return ContentManager::InstallNSP(system.get(), vfs.get(), file.toStdString(), | ||
| 3286 | progress_callback); | ||
| 3287 | }); | ||
| 3283 | 3288 | ||
| 3284 | while (!future.isFinished()) { | 3289 | while (!future.isFinished()) { |
| 3285 | QCoreApplication::processEvents(); | 3290 | QCoreApplication::processEvents(); |
| @@ -3295,16 +3300,16 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 3295 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); | 3300 | std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
| 3296 | 3301 | ||
| 3297 | switch (result) { | 3302 | switch (result) { |
| 3298 | case InstallResult::Success: | 3303 | case ContentManager::InstallResult::Success: |
| 3299 | new_files.append(QFileInfo(file).fileName()); | 3304 | new_files.append(QFileInfo(file).fileName()); |
| 3300 | break; | 3305 | break; |
| 3301 | case InstallResult::Overwrite: | 3306 | case ContentManager::InstallResult::Overwrite: |
| 3302 | overwritten_files.append(QFileInfo(file).fileName()); | 3307 | overwritten_files.append(QFileInfo(file).fileName()); |
| 3303 | break; | 3308 | break; |
| 3304 | case InstallResult::Failure: | 3309 | case ContentManager::InstallResult::Failure: |
| 3305 | failed_files.append(QFileInfo(file).fileName()); | 3310 | failed_files.append(QFileInfo(file).fileName()); |
| 3306 | break; | 3311 | break; |
| 3307 | case InstallResult::BaseInstallAttempted: | 3312 | case ContentManager::InstallResult::BaseInstallAttempted: |
| 3308 | failed_files.append(QFileInfo(file).fileName()); | 3313 | failed_files.append(QFileInfo(file).fileName()); |
| 3309 | detected_base_install = true; | 3314 | detected_base_install = true; |
| 3310 | break; | 3315 | break; |
| @@ -3338,96 +3343,7 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 3338 | ui->action_Install_File_NAND->setEnabled(true); | 3343 | ui->action_Install_File_NAND->setEnabled(true); |
| 3339 | } | 3344 | } |
| 3340 | 3345 | ||
| 3341 | InstallResult GMainWindow::InstallNSP(const QString& filename) { | 3346 | ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) { |
| 3342 | const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, | ||
| 3343 | const FileSys::VirtualFile& dest, std::size_t block_size) { | ||
| 3344 | if (src == nullptr || dest == nullptr) { | ||
| 3345 | return false; | ||
| 3346 | } | ||
| 3347 | if (!dest->Resize(src->GetSize())) { | ||
| 3348 | return false; | ||
| 3349 | } | ||
| 3350 | |||
| 3351 | std::vector<u8> buffer(CopyBufferSize); | ||
| 3352 | |||
| 3353 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { | ||
| 3354 | if (install_progress->wasCanceled()) { | ||
| 3355 | dest->Resize(0); | ||
| 3356 | return false; | ||
| 3357 | } | ||
| 3358 | |||
| 3359 | emit UpdateInstallProgress(); | ||
| 3360 | |||
| 3361 | const auto read = src->Read(buffer.data(), buffer.size(), i); | ||
| 3362 | dest->Write(buffer.data(), read, i); | ||
| 3363 | } | ||
| 3364 | return true; | ||
| 3365 | }; | ||
| 3366 | |||
| 3367 | std::shared_ptr<FileSys::NSP> nsp; | ||
| 3368 | if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { | ||
| 3369 | nsp = std::make_shared<FileSys::NSP>( | ||
| 3370 | vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); | ||
| 3371 | if (nsp->IsExtractedType()) { | ||
| 3372 | return InstallResult::Failure; | ||
| 3373 | } | ||
| 3374 | } else { | ||
| 3375 | return InstallResult::Failure; | ||
| 3376 | } | ||
| 3377 | |||
| 3378 | if (nsp->GetStatus() != Loader::ResultStatus::Success) { | ||
| 3379 | return InstallResult::Failure; | ||
| 3380 | } | ||
| 3381 | const auto res = system->GetFileSystemController().GetUserNANDContents()->InstallEntry( | ||
| 3382 | *nsp, true, qt_raw_copy); | ||
| 3383 | switch (res) { | ||
| 3384 | case FileSys::InstallResult::Success: | ||
| 3385 | return InstallResult::Success; | ||
| 3386 | case FileSys::InstallResult::OverwriteExisting: | ||
| 3387 | return InstallResult::Overwrite; | ||
| 3388 | case FileSys::InstallResult::ErrorBaseInstall: | ||
| 3389 | return InstallResult::BaseInstallAttempted; | ||
| 3390 | default: | ||
| 3391 | return InstallResult::Failure; | ||
| 3392 | } | ||
| 3393 | } | ||
| 3394 | |||
| 3395 | InstallResult GMainWindow::InstallNCA(const QString& filename) { | ||
| 3396 | const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, | ||
| 3397 | const FileSys::VirtualFile& dest, std::size_t block_size) { | ||
| 3398 | if (src == nullptr || dest == nullptr) { | ||
| 3399 | return false; | ||
| 3400 | } | ||
| 3401 | if (!dest->Resize(src->GetSize())) { | ||
| 3402 | return false; | ||
| 3403 | } | ||
| 3404 | |||
| 3405 | std::vector<u8> buffer(CopyBufferSize); | ||
| 3406 | |||
| 3407 | for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { | ||
| 3408 | if (install_progress->wasCanceled()) { | ||
| 3409 | dest->Resize(0); | ||
| 3410 | return false; | ||
| 3411 | } | ||
| 3412 | |||
| 3413 | emit UpdateInstallProgress(); | ||
| 3414 | |||
| 3415 | const auto read = src->Read(buffer.data(), buffer.size(), i); | ||
| 3416 | dest->Write(buffer.data(), read, i); | ||
| 3417 | } | ||
| 3418 | return true; | ||
| 3419 | }; | ||
| 3420 | |||
| 3421 | const auto nca = | ||
| 3422 | std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); | ||
| 3423 | const auto id = nca->GetStatus(); | ||
| 3424 | |||
| 3425 | // Game updates necessary are missing base RomFS | ||
| 3426 | if (id != Loader::ResultStatus::Success && | ||
| 3427 | id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { | ||
| 3428 | return InstallResult::Failure; | ||
| 3429 | } | ||
| 3430 | |||
| 3431 | const QStringList tt_options{tr("System Application"), | 3347 | const QStringList tt_options{tr("System Application"), |
| 3432 | tr("System Archive"), | 3348 | tr("System Archive"), |
| 3433 | tr("System Application Update"), | 3349 | tr("System Application Update"), |
| @@ -3448,7 +3364,7 @@ InstallResult GMainWindow::InstallNCA(const QString& filename) { | |||
| 3448 | if (!ok || index == -1) { | 3364 | if (!ok || index == -1) { |
| 3449 | QMessageBox::warning(this, tr("Failed to Install"), | 3365 | QMessageBox::warning(this, tr("Failed to Install"), |
| 3450 | tr("The title type you selected for the NCA is invalid.")); | 3366 | tr("The title type you selected for the NCA is invalid.")); |
| 3451 | return InstallResult::Failure; | 3367 | return ContentManager::InstallResult::Failure; |
| 3452 | } | 3368 | } |
| 3453 | 3369 | ||
| 3454 | // If index is equal to or past Game, add the jump in TitleType. | 3370 | // If index is equal to or past Game, add the jump in TitleType. |
| @@ -3462,15 +3378,15 @@ InstallResult GMainWindow::InstallNCA(const QString& filename) { | |||
| 3462 | auto* registered_cache = is_application ? fs_controller.GetUserNANDContents() | 3378 | auto* registered_cache = is_application ? fs_controller.GetUserNANDContents() |
| 3463 | : fs_controller.GetSystemNANDContents(); | 3379 | : fs_controller.GetSystemNANDContents(); |
| 3464 | 3380 | ||
| 3465 | const auto res = registered_cache->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), | 3381 | const auto progress_callback = [this](size_t size, size_t progress) { |
| 3466 | true, qt_raw_copy); | 3382 | emit UpdateInstallProgress(); |
| 3467 | if (res == FileSys::InstallResult::Success) { | 3383 | if (install_progress->wasCanceled()) { |
| 3468 | return InstallResult::Success; | 3384 | return true; |
| 3469 | } else if (res == FileSys::InstallResult::OverwriteExisting) { | 3385 | } |
| 3470 | return InstallResult::Overwrite; | 3386 | return false; |
| 3471 | } else { | 3387 | }; |
| 3472 | return InstallResult::Failure; | 3388 | return ContentManager::InstallNCA(vfs.get(), filename.toStdString(), registered_cache, |
| 3473 | } | 3389 | static_cast<FileSys::TitleType>(index), progress_callback); |
| 3474 | } | 3390 | } |
| 3475 | 3391 | ||
| 3476 | void GMainWindow::OnMenuRecentFile() { | 3392 | void GMainWindow::OnMenuRecentFile() { |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 366e806d5..280fae5c3 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -16,6 +16,7 @@ | |||
| 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 "configuration/qt_config.h" |
| 19 | #include "frontend_common/content_manager.h" | ||
| 19 | #include "input_common/drivers/tas_input.h" | 20 | #include "input_common/drivers/tas_input.h" |
| 20 | #include "yuzu/compatibility_list.h" | 21 | #include "yuzu/compatibility_list.h" |
| 21 | #include "yuzu/hotkeys.h" | 22 | #include "yuzu/hotkeys.h" |
| @@ -124,13 +125,6 @@ enum class EmulatedDirectoryTarget { | |||
| 124 | SDMC, | 125 | SDMC, |
| 125 | }; | 126 | }; |
| 126 | 127 | ||
| 127 | enum class InstallResult { | ||
| 128 | Success, | ||
| 129 | Overwrite, | ||
| 130 | Failure, | ||
| 131 | BaseInstallAttempted, | ||
| 132 | }; | ||
| 133 | |||
| 134 | enum class ReinitializeKeyBehavior { | 128 | enum class ReinitializeKeyBehavior { |
| 135 | NoWarning, | 129 | NoWarning, |
| 136 | Warning, | 130 | Warning, |
| @@ -427,8 +421,7 @@ private: | |||
| 427 | void RemoveCacheStorage(u64 program_id); | 421 | void RemoveCacheStorage(u64 program_id); |
| 428 | bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, | 422 | bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, |
| 429 | u64* selected_title_id, u8* selected_content_record_type); | 423 | u64* selected_title_id, u8* selected_content_record_type); |
| 430 | InstallResult InstallNSP(const QString& filename); | 424 | ContentManager::InstallResult InstallNCA(const QString& filename); |
| 431 | InstallResult InstallNCA(const QString& filename); | ||
| 432 | void MigrateConfigFiles(); | 425 | void MigrateConfigFiles(); |
| 433 | void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, | 426 | void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, |
| 434 | std::string_view gpu_vendor = {}); | 427 | std::string_view gpu_vendor = {}); |
| @@ -523,6 +516,8 @@ private: | |||
| 523 | std::unique_ptr<EmuThread> emu_thread; | 516 | std::unique_ptr<EmuThread> emu_thread; |
| 524 | // The path to the game currently running | 517 | // The path to the game currently running |
| 525 | QString current_game_path; | 518 | QString current_game_path; |
| 519 | // Whether a user was set on the command line (skips UserSelector if it's forced to show up) | ||
| 520 | bool user_flag_cmd_line = false; | ||
| 526 | 521 | ||
| 527 | bool auto_paused = false; | 522 | bool auto_paused = false; |
| 528 | bool auto_muted = false; | 523 | bool auto_muted = false; |
diff --git a/src/yuzu_cmd/sdl_config.cpp b/src/yuzu_cmd/sdl_config.cpp index e81bf5d45..995114510 100644 --- a/src/yuzu_cmd/sdl_config.cpp +++ b/src/yuzu_cmd/sdl_config.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #define SDL_MAIN_HANDLED | 5 | #define SDL_MAIN_HANDLED |
| 6 | #include <SDL.h> | 6 | #include <SDL.h> |
| 7 | 7 | ||
| 8 | #include "common/logging/log.h" | ||
| 8 | #include "input_common/main.h" | 9 | #include "input_common/main.h" |
| 9 | #include "sdl_config.h" | 10 | #include "sdl_config.h" |
| 10 | 11 | ||
| @@ -64,7 +65,7 @@ void SdlConfig::ReloadAllValues() { | |||
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | void SdlConfig::SaveAllValues() { | 67 | void SdlConfig::SaveAllValues() { |
| 67 | Save(); | 68 | SaveValues(); |
| 68 | SaveSdlValues(); | 69 | SaveSdlValues(); |
| 69 | } | 70 | } |
| 70 | 71 | ||
| @@ -177,6 +178,7 @@ void SdlConfig::ReadHidbusValues() { | |||
| 177 | } | 178 | } |
| 178 | 179 | ||
| 179 | void SdlConfig::SaveSdlValues() { | 180 | void SdlConfig::SaveSdlValues() { |
| 181 | LOG_DEBUG(Config, "Saving SDL configuration values"); | ||
| 180 | SaveSdlControlValues(); | 182 | SaveSdlControlValues(); |
| 181 | 183 | ||
| 182 | WriteToIni(); | 184 | WriteToIni(); |