diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/android/app/src/main/AndroidManifest.xml | 3 | ||||
| -rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | 9 | ||||
| -rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt | 219 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/native.cpp | 16 | ||||
| -rw-r--r-- | src/android/app/src/main/res/values/strings.xml | 10 | ||||
| -rw-r--r-- | src/android/app/src/main/res/xml/game_mode_config.xml | 7 | ||||
| -rw-r--r-- | src/core/file_sys/savedata_factory.cpp | 9 | ||||
| -rw-r--r-- | src/core/file_sys/savedata_factory.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid_system_server.cpp | 60 | ||||
| -rw-r--r-- | src/core/hle/service/hid/hid_system_server.h | 6 | ||||
| -rw-r--r-- | src/hid_core/resource_manager.cpp | 1 | ||||
| -rw-r--r-- | src/hid_core/resources/applet_resource.cpp | 34 | ||||
| -rw-r--r-- | src/hid_core/resources/npad/npad.cpp | 5 | ||||
| -rw-r--r-- | src/hid_core/resources/npad/npad_resource.cpp | 4 |
14 files changed, 357 insertions, 27 deletions
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index f10131b24..f011bd696 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml | |||
| @@ -31,6 +31,9 @@ SPDX-License-Identifier: GPL-3.0-or-later | |||
| 31 | android:dataExtractionRules="@xml/data_extraction_rules_api_31" | 31 | android:dataExtractionRules="@xml/data_extraction_rules_api_31" |
| 32 | android:enableOnBackInvokedCallback="true"> | 32 | android:enableOnBackInvokedCallback="true"> |
| 33 | 33 | ||
| 34 | <meta-data android:name="android.game_mode_config" | ||
| 35 | android:resource="@xml/game_mode_config" /> | ||
| 36 | |||
| 34 | <activity | 37 | <activity |
| 35 | android:name="org.yuzu.yuzu_emu.ui.main.MainActivity" | 38 | android:name="org.yuzu.yuzu_emu.ui.main.MainActivity" |
| 36 | android:exported="true" | 39 | android:exported="true" |
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 010c44951..b7556e353 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 | |||
| @@ -548,6 +548,15 @@ object NativeLibrary { | |||
| 548 | external fun getSavePath(programId: String): String | 548 | external fun getSavePath(programId: String): String |
| 549 | 549 | ||
| 550 | /** | 550 | /** |
| 551 | * Gets the root save directory for the default profile as either | ||
| 552 | * /user/save/account/<user id raw string> or /user/save/000...000/<user id> | ||
| 553 | * | ||
| 554 | * @param future If true, returns the /user/save/account/... directory | ||
| 555 | * @return Save data path that may not exist yet | ||
| 556 | */ | ||
| 557 | external fun getDefaultProfileSaveDataRoot(future: Boolean): String | ||
| 558 | |||
| 559 | /** | ||
| 551 | * Adds a file to the manual filesystem provider in our EmulationSession instance | 560 | * Adds a file to the manual filesystem provider in our EmulationSession instance |
| 552 | * @param path Path to the file we're adding. Can be a string representation of a [Uri] or | 561 | * @param path Path to the file we're adding. Can be a string representation of a [Uri] or |
| 553 | * a normal path | 562 | * a normal path |
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 569727b90..5b4bf2c9f 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 | |||
| @@ -7,20 +7,39 @@ import android.os.Bundle | |||
| 7 | import android.view.LayoutInflater | 7 | import android.view.LayoutInflater |
| 8 | import android.view.View | 8 | import android.view.View |
| 9 | import android.view.ViewGroup | 9 | import android.view.ViewGroup |
| 10 | import android.widget.Toast | ||
| 11 | import androidx.activity.result.contract.ActivityResultContracts | ||
| 10 | import androidx.core.view.ViewCompat | 12 | import androidx.core.view.ViewCompat |
| 11 | import androidx.core.view.WindowInsetsCompat | 13 | import androidx.core.view.WindowInsetsCompat |
| 12 | import androidx.core.view.updatePadding | 14 | import androidx.core.view.updatePadding |
| 13 | import androidx.fragment.app.Fragment | 15 | import androidx.fragment.app.Fragment |
| 14 | import androidx.fragment.app.activityViewModels | 16 | import androidx.fragment.app.activityViewModels |
| 17 | import androidx.lifecycle.Lifecycle | ||
| 18 | import androidx.lifecycle.lifecycleScope | ||
| 19 | import androidx.lifecycle.repeatOnLifecycle | ||
| 15 | import androidx.navigation.findNavController | 20 | import androidx.navigation.findNavController |
| 16 | import androidx.recyclerview.widget.GridLayoutManager | 21 | import androidx.recyclerview.widget.GridLayoutManager |
| 17 | import com.google.android.material.transition.MaterialSharedAxis | 22 | import com.google.android.material.transition.MaterialSharedAxis |
| 23 | import kotlinx.coroutines.Dispatchers | ||
| 24 | import kotlinx.coroutines.launch | ||
| 25 | import kotlinx.coroutines.withContext | ||
| 26 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 18 | import org.yuzu.yuzu_emu.R | 27 | import org.yuzu.yuzu_emu.R |
| 28 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 19 | import org.yuzu.yuzu_emu.adapters.InstallableAdapter | 29 | import org.yuzu.yuzu_emu.adapters.InstallableAdapter |
| 20 | import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding | 30 | import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding |
| 21 | import org.yuzu.yuzu_emu.model.HomeViewModel | 31 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 22 | import org.yuzu.yuzu_emu.model.Installable | 32 | import org.yuzu.yuzu_emu.model.Installable |
| 33 | import org.yuzu.yuzu_emu.model.TaskState | ||
| 23 | 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 | ||
| 36 | import org.yuzu.yuzu_emu.utils.FileUtil | ||
| 37 | import java.io.BufferedInputStream | ||
| 38 | import java.io.BufferedOutputStream | ||
| 39 | import java.io.File | ||
| 40 | import java.math.BigInteger | ||
| 41 | import java.time.LocalDateTime | ||
| 42 | import java.time.format.DateTimeFormatter | ||
| 24 | 43 | ||
| 25 | class InstallableFragment : Fragment() { | 44 | class InstallableFragment : Fragment() { |
| 26 | private var _binding: FragmentInstallablesBinding? = null | 45 | private var _binding: FragmentInstallablesBinding? = null |
| @@ -56,6 +75,17 @@ class InstallableFragment : Fragment() { | |||
| 56 | binding.root.findNavController().popBackStack() | 75 | binding.root.findNavController().popBackStack() |
| 57 | } | 76 | } |
| 58 | 77 | ||
| 78 | viewLifecycleOwner.lifecycleScope.launch { | ||
| 79 | repeatOnLifecycle(Lifecycle.State.CREATED) { | ||
| 80 | homeViewModel.openImportSaves.collect { | ||
| 81 | if (it) { | ||
| 82 | importSaves.launch(arrayOf("application/zip")) | ||
| 83 | homeViewModel.setOpenImportSaves(false) | ||
| 84 | } | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 59 | val installables = listOf( | 89 | val installables = listOf( |
| 60 | Installable( | 90 | Installable( |
| 61 | R.string.user_data, | 91 | R.string.user_data, |
| @@ -64,6 +94,43 @@ class InstallableFragment : Fragment() { | |||
| 64 | export = { mainActivity.exportUserData.launch("export.zip") } | 94 | export = { mainActivity.exportUserData.launch("export.zip") } |
| 65 | ), | 95 | ), |
| 66 | Installable( | 96 | Installable( |
| 97 | R.string.manage_save_data, | ||
| 98 | R.string.manage_save_data_description, | ||
| 99 | install = { | ||
| 100 | MessageDialogFragment.newInstance( | ||
| 101 | requireActivity(), | ||
| 102 | titleId = R.string.import_save_warning, | ||
| 103 | descriptionId = R.string.import_save_warning_description, | ||
| 104 | positiveAction = { homeViewModel.setOpenImportSaves(true) } | ||
| 105 | ).show(parentFragmentManager, MessageDialogFragment.TAG) | ||
| 106 | }, | ||
| 107 | export = { | ||
| 108 | val oldSaveDataFolder = File( | ||
| 109 | "${DirectoryInitialization.userDirectory}/nand" + | ||
| 110 | NativeLibrary.getDefaultProfileSaveDataRoot(false) | ||
| 111 | ) | ||
| 112 | val futureSaveDataFolder = File( | ||
| 113 | "${DirectoryInitialization.userDirectory}/nand" + | ||
| 114 | NativeLibrary.getDefaultProfileSaveDataRoot(true) | ||
| 115 | ) | ||
| 116 | if (!oldSaveDataFolder.exists() && !futureSaveDataFolder.exists()) { | ||
| 117 | Toast.makeText( | ||
| 118 | YuzuApplication.appContext, | ||
| 119 | R.string.no_save_data_found, | ||
| 120 | Toast.LENGTH_SHORT | ||
| 121 | ).show() | ||
| 122 | return@Installable | ||
| 123 | } else { | ||
| 124 | exportSaves.launch( | ||
| 125 | "${getString(R.string.save_data)} " + | ||
| 126 | LocalDateTime.now().format( | ||
| 127 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") | ||
| 128 | ) | ||
| 129 | ) | ||
| 130 | } | ||
| 131 | } | ||
| 132 | ), | ||
| 133 | Installable( | ||
| 67 | R.string.install_game_content, | 134 | R.string.install_game_content, |
| 68 | R.string.install_game_content_description, | 135 | R.string.install_game_content_description, |
| 69 | install = { mainActivity.installGameUpdate.launch(arrayOf("*/*")) } | 136 | install = { mainActivity.installGameUpdate.launch(arrayOf("*/*")) } |
| @@ -121,4 +188,156 @@ class InstallableFragment : Fragment() { | |||
| 121 | 188 | ||
| 122 | windowInsets | 189 | windowInsets |
| 123 | } | 190 | } |
| 191 | |||
| 192 | private val importSaves = | ||
| 193 | registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> | ||
| 194 | if (result == null) { | ||
| 195 | return@registerForActivityResult | ||
| 196 | } | ||
| 197 | |||
| 198 | val inputZip = requireContext().contentResolver.openInputStream(result) | ||
| 199 | val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/") | ||
| 200 | cacheSaveDir.mkdir() | ||
| 201 | |||
| 202 | if (inputZip == null) { | ||
| 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(), | ||
| 213 | R.string.save_files_importing, | ||
| 214 | false | ||
| 215 | ) { | ||
| 216 | try { | ||
| 217 | FileUtil.unzipToInternalStorage(BufferedInputStream(inputZip), cacheSaveDir) | ||
| 218 | val files = cacheSaveDir.listFiles() | ||
| 219 | var successfulImports = 0 | ||
| 220 | var failedImports = 0 | ||
| 221 | if (files != null) { | ||
| 222 | for (file in files) { | ||
| 223 | if (file.isDirectory) { | ||
| 224 | val baseSaveDir = | ||
| 225 | NativeLibrary.getSavePath(BigInteger(file.name, 16).toString()) | ||
| 226 | if (baseSaveDir.isEmpty()) { | ||
| 227 | failedImports++ | ||
| 228 | continue | ||
| 229 | } | ||
| 230 | |||
| 231 | val internalSaveFolder = File( | ||
| 232 | "${DirectoryInitialization.userDirectory}/nand$baseSaveDir" | ||
| 233 | ) | ||
| 234 | internalSaveFolder.deleteRecursively() | ||
| 235 | internalSaveFolder.mkdir() | ||
| 236 | file.copyRecursively(target = internalSaveFolder, overwrite = true) | ||
| 237 | successfulImports++ | ||
| 238 | } | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | withContext(Dispatchers.Main) { | ||
| 243 | if (successfulImports == 0) { | ||
| 244 | MessageDialogFragment.newInstance( | ||
| 245 | requireActivity(), | ||
| 246 | titleId = R.string.save_file_invalid_zip_structure, | ||
| 247 | descriptionId = R.string.save_file_invalid_zip_structure_description | ||
| 248 | ).show(parentFragmentManager, MessageDialogFragment.TAG) | ||
| 249 | return@withContext | ||
| 250 | } | ||
| 251 | val successString = if (failedImports > 0) { | ||
| 252 | """ | ||
| 253 | ${ | ||
| 254 | requireContext().resources.getQuantityString( | ||
| 255 | R.plurals.saves_import_success, | ||
| 256 | successfulImports, | ||
| 257 | successfulImports | ||
| 258 | ) | ||
| 259 | } | ||
| 260 | ${ | ||
| 261 | requireContext().resources.getQuantityString( | ||
| 262 | R.plurals.saves_import_failed, | ||
| 263 | failedImports, | ||
| 264 | failedImports | ||
| 265 | ) | ||
| 266 | } | ||
| 267 | """ | ||
| 268 | } else { | ||
| 269 | requireContext().resources.getQuantityString( | ||
| 270 | R.plurals.saves_import_success, | ||
| 271 | successfulImports, | ||
| 272 | successfulImports | ||
| 273 | ) | ||
| 274 | } | ||
| 275 | MessageDialogFragment.newInstance( | ||
| 276 | requireActivity(), | ||
| 277 | titleId = R.string.import_complete, | ||
| 278 | descriptionString = successString | ||
| 279 | ).show(parentFragmentManager, MessageDialogFragment.TAG) | ||
| 280 | } | ||
| 281 | |||
| 282 | cacheSaveDir.deleteRecursively() | ||
| 283 | } catch (e: Exception) { | ||
| 284 | Toast.makeText( | ||
| 285 | YuzuApplication.appContext, | ||
| 286 | getString(R.string.fatal_error), | ||
| 287 | Toast.LENGTH_LONG | ||
| 288 | ).show() | ||
| 289 | } | ||
| 290 | }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG) | ||
| 291 | } | ||
| 292 | |||
| 293 | private val exportSaves = registerForActivityResult( | ||
| 294 | ActivityResultContracts.CreateDocument("application/zip") | ||
| 295 | ) { result -> | ||
| 296 | if (result == null) { | ||
| 297 | return@registerForActivityResult | ||
| 298 | } | ||
| 299 | |||
| 300 | IndeterminateProgressDialogFragment.newInstance( | ||
| 301 | requireActivity(), | ||
| 302 | R.string.save_files_exporting, | ||
| 303 | false | ||
| 304 | ) { | ||
| 305 | val cacheSaveDir = File("${requireContext().cacheDir.path}/saves/") | ||
| 306 | cacheSaveDir.mkdir() | ||
| 307 | |||
| 308 | val oldSaveDataFolder = File( | ||
| 309 | "${DirectoryInitialization.userDirectory}/nand" + | ||
| 310 | NativeLibrary.getDefaultProfileSaveDataRoot(false) | ||
| 311 | ) | ||
| 312 | if (oldSaveDataFolder.exists()) { | ||
| 313 | oldSaveDataFolder.copyRecursively(cacheSaveDir) | ||
| 314 | } | ||
| 315 | |||
| 316 | val futureSaveDataFolder = File( | ||
| 317 | "${DirectoryInitialization.userDirectory}/nand" + | ||
| 318 | NativeLibrary.getDefaultProfileSaveDataRoot(true) | ||
| 319 | ) | ||
| 320 | if (futureSaveDataFolder.exists()) { | ||
| 321 | futureSaveDataFolder.copyRecursively(cacheSaveDir) | ||
| 322 | } | ||
| 323 | |||
| 324 | val saveFilesTotal = cacheSaveDir.listFiles()?.size ?: 0 | ||
| 325 | if (saveFilesTotal == 0) { | ||
| 326 | cacheSaveDir.deleteRecursively() | ||
| 327 | return@newInstance getString(R.string.no_save_data_found) | ||
| 328 | } | ||
| 329 | |||
| 330 | val zipResult = FileUtil.zipFromInternalStorage( | ||
| 331 | cacheSaveDir, | ||
| 332 | cacheSaveDir.path, | ||
| 333 | BufferedOutputStream(requireContext().contentResolver.openOutputStream(result)) | ||
| 334 | ) | ||
| 335 | cacheSaveDir.deleteRecursively() | ||
| 336 | |||
| 337 | return@newInstance when (zipResult) { | ||
| 338 | TaskState.Completed -> getString(R.string.export_success) | ||
| 339 | TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed) | ||
| 340 | } | ||
| 341 | }.show(parentFragmentManager, IndeterminateProgressDialogFragment.TAG) | ||
| 342 | } | ||
| 124 | } | 343 | } |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 056920a4a..136c8dee6 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -862,6 +862,9 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAddonsForFile(JNIEnv* env, | |||
| 862 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, | 862 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, |
| 863 | jstring jprogramId) { | 863 | jstring jprogramId) { |
| 864 | auto program_id = EmulationSession::GetProgramId(env, jprogramId); | 864 | auto program_id = EmulationSession::GetProgramId(env, jprogramId); |
| 865 | if (program_id == 0) { | ||
| 866 | return ToJString(env, ""); | ||
| 867 | } | ||
| 865 | 868 | ||
| 866 | auto& system = EmulationSession::GetInstance().System(); | 869 | auto& system = EmulationSession::GetInstance().System(); |
| 867 | 870 | ||
| @@ -880,6 +883,19 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j | |||
| 880 | return ToJString(env, user_save_data_path); | 883 | return ToJString(env, user_save_data_path); |
| 881 | } | 884 | } |
| 882 | 885 | ||
| 886 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIEnv* env, | ||
| 887 | jobject jobj, | ||
| 888 | jboolean jfuture) { | ||
| 889 | Service::Account::ProfileManager manager; | ||
| 890 | // TODO: Pass in a selected user once we get the relevant UI working | ||
| 891 | const auto user_id = manager.GetUser(static_cast<std::size_t>(0)); | ||
| 892 | ASSERT(user_id); | ||
| 893 | |||
| 894 | const auto user_save_data_root = | ||
| 895 | FileSys::SaveDataFactory::GetUserGameSaveDataRoot(user_id->AsU128(), jfuture); | ||
| 896 | return ToJString(env, user_save_data_root); | ||
| 897 | } | ||
| 898 | |||
| 883 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj, | 899 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj, |
| 884 | jstring jpath) { | 900 | jstring jpath) { |
| 885 | EmulationSession::GetInstance().ConfigureFilesystemProvider(GetJString(env, jpath)); | 901 | EmulationSession::GetInstance().ConfigureFilesystemProvider(GetJString(env, jpath)); |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 83aa1b781..3bb92ad67 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -133,6 +133,15 @@ | |||
| 133 | <string name="add_game_folder">Add game folder</string> | 133 | <string name="add_game_folder">Add game folder</string> |
| 134 | <string name="folder_already_added">This folder was already added!</string> | 134 | <string name="folder_already_added">This folder was already added!</string> |
| 135 | <string name="game_folder_properties">Game folder properties</string> | 135 | <string name="game_folder_properties">Game folder properties</string> |
| 136 | <plurals name="saves_import_failed"> | ||
| 137 | <item quantity="one">Failed to import %d save</item> | ||
| 138 | <item quantity="other">Failed to import %d saves</item> | ||
| 139 | </plurals> | ||
| 140 | <plurals name="saves_import_success"> | ||
| 141 | <item quantity="one">Successfully imported %d save</item> | ||
| 142 | <item quantity="other">Successfully imported %d saves</item> | ||
| 143 | </plurals> | ||
| 144 | <string name="no_save_data_found">No save data found</string> | ||
| 136 | 145 | ||
| 137 | <!-- Applet launcher strings --> | 146 | <!-- Applet launcher strings --> |
| 138 | <string name="applets">Applet launcher</string> | 147 | <string name="applets">Applet launcher</string> |
| @@ -276,6 +285,7 @@ | |||
| 276 | <string name="global">Global</string> | 285 | <string name="global">Global</string> |
| 277 | <string name="custom">Custom</string> | 286 | <string name="custom">Custom</string> |
| 278 | <string name="notice">Notice</string> | 287 | <string name="notice">Notice</string> |
| 288 | <string name="import_complete">Import complete</string> | ||
| 279 | 289 | ||
| 280 | <!-- GPU driver installation --> | 290 | <!-- GPU driver installation --> |
| 281 | <string name="select_gpu_driver">Select GPU driver</string> | 291 | <string name="select_gpu_driver">Select GPU driver</string> |
diff --git a/src/android/app/src/main/res/xml/game_mode_config.xml b/src/android/app/src/main/res/xml/game_mode_config.xml new file mode 100644 index 000000000..b28dd3a11 --- /dev/null +++ b/src/android/app/src/main/res/xml/game_mode_config.xml | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <game-mode-config | ||
| 3 | xmlns:android="http://schemas.android.com/apk/res/android" | ||
| 4 | android:supportsBatteryGameMode="true" | ||
| 5 | android:supportsPerformanceGameMode="true" | ||
| 6 | android:allowGameDownscaling="false" | ||
| 7 | android:allowGameFpsOverride="false"/> | ||
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index 8d5d593e8..12b3bd797 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -189,6 +189,15 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir, | |||
| 189 | } | 189 | } |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future) { | ||
| 193 | if (future) { | ||
| 194 | Common::UUID uuid; | ||
| 195 | std::memcpy(uuid.uuid.data(), user_id.data(), sizeof(Common::UUID)); | ||
| 196 | return fmt::format("/user/save/account/{}", uuid.RawString()); | ||
| 197 | } | ||
| 198 | return fmt::format("/user/save/{:016X}/{:016X}{:016X}", 0, user_id[1], user_id[0]); | ||
| 199 | } | ||
| 200 | |||
| 192 | SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, | 201 | SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, |
| 193 | u128 user_id) const { | 202 | u128 user_id) const { |
| 194 | const auto path = | 203 | const auto path = |
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index e3a0f8cef..fd4887e99 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h | |||
| @@ -101,6 +101,7 @@ public: | |||
| 101 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); | 101 | static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space); |
| 102 | static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space, | 102 | static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space, |
| 103 | SaveDataType type, u64 title_id, u128 user_id, u64 save_id); | 103 | SaveDataType type, u64 title_id, u128 user_id, u64 save_id); |
| 104 | static std::string GetUserGameSaveDataRoot(u128 user_id, bool future); | ||
| 104 | 105 | ||
| 105 | SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; | 106 | SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; |
| 106 | void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, | 107 | void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, |
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp index 027c56025..2a65615e8 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp | |||
| @@ -81,7 +81,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour | |||
| 81 | {522, nullptr, "SetJoyConRailEnabled"}, | 81 | {522, nullptr, "SetJoyConRailEnabled"}, |
| 82 | {523, nullptr, "IsJoyConRailEnabled"}, | 82 | {523, nullptr, "IsJoyConRailEnabled"}, |
| 83 | {524, nullptr, "IsHandheldHidsEnabled"}, | 83 | {524, nullptr, "IsHandheldHidsEnabled"}, |
| 84 | {525, nullptr, "IsJoyConAttachedOnAllRail"}, | 84 | {525, &IHidSystemServer::IsJoyConAttachedOnAllRail, "IsJoyConAttachedOnAllRail"}, |
| 85 | {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, | 85 | {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"}, |
| 86 | {541, nullptr, "GetPlayReportControllerUsages"}, | 86 | {541, nullptr, "GetPlayReportControllerUsages"}, |
| 87 | {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, | 87 | {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"}, |
| @@ -131,7 +131,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour | |||
| 131 | {1001, nullptr, "GetFirmwareVersion"}, | 131 | {1001, nullptr, "GetFirmwareVersion"}, |
| 132 | {1002, nullptr, "GetAvailableFirmwareVersion"}, | 132 | {1002, nullptr, "GetAvailableFirmwareVersion"}, |
| 133 | {1003, nullptr, "IsFirmwareUpdateAvailable"}, | 133 | {1003, nullptr, "IsFirmwareUpdateAvailable"}, |
| 134 | {1004, nullptr, "CheckFirmwareUpdateRequired"}, | 134 | {1004, &IHidSystemServer::CheckFirmwareUpdateRequired, "CheckFirmwareUpdateRequired"}, |
| 135 | {1005, nullptr, "StartFirmwareUpdate"}, | 135 | {1005, nullptr, "StartFirmwareUpdate"}, |
| 136 | {1006, nullptr, "AbortFirmwareUpdate"}, | 136 | {1006, nullptr, "AbortFirmwareUpdate"}, |
| 137 | {1007, nullptr, "GetFirmwareUpdateState"}, | 137 | {1007, nullptr, "GetFirmwareUpdateState"}, |
| @@ -144,9 +144,9 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour | |||
| 144 | {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"}, | 144 | {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"}, |
| 145 | {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"}, | 145 | {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"}, |
| 146 | {1100, nullptr, "GetHidbusSystemServiceObject"}, | 146 | {1100, nullptr, "GetHidbusSystemServiceObject"}, |
| 147 | {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"}, | 147 | {1120, &IHidSystemServer::SetFirmwareHotfixUpdateSkipEnabled, "SetFirmwareHotfixUpdateSkipEnabled"}, |
| 148 | {1130, nullptr, "InitializeUsbFirmwareUpdate"}, | 148 | {1130, &IHidSystemServer::InitializeUsbFirmwareUpdate, "InitializeUsbFirmwareUpdate"}, |
| 149 | {1131, nullptr, "FinalizeUsbFirmwareUpdate"}, | 149 | {1131, &IHidSystemServer::FinalizeUsbFirmwareUpdate, "FinalizeUsbFirmwareUpdate"}, |
| 150 | {1132, nullptr, "CheckUsbFirmwareUpdateRequired"}, | 150 | {1132, nullptr, "CheckUsbFirmwareUpdateRequired"}, |
| 151 | {1133, nullptr, "StartUsbFirmwareUpdate"}, | 151 | {1133, nullptr, "StartUsbFirmwareUpdate"}, |
| 152 | {1134, nullptr, "GetUsbFirmwareUpdateState"}, | 152 | {1134, nullptr, "GetUsbFirmwareUpdateState"}, |
| @@ -196,7 +196,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour | |||
| 196 | {1268, nullptr, "DeleteButtonConfigStorageFull"}, | 196 | {1268, nullptr, "DeleteButtonConfigStorageFull"}, |
| 197 | {1269, nullptr, "DeleteButtonConfigStorageLeft"}, | 197 | {1269, nullptr, "DeleteButtonConfigStorageLeft"}, |
| 198 | {1270, nullptr, "DeleteButtonConfigStorageRight"}, | 198 | {1270, nullptr, "DeleteButtonConfigStorageRight"}, |
| 199 | {1271, nullptr, "IsUsingCustomButtonConfig"}, | 199 | {1271, &IHidSystemServer::IsUsingCustomButtonConfig, "IsUsingCustomButtonConfig"}, |
| 200 | {1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, | 200 | {1272, nullptr, "IsAnyCustomButtonConfigEnabled"}, |
| 201 | {1273, nullptr, "SetAllCustomButtonConfigEnabled"}, | 201 | {1273, nullptr, "SetAllCustomButtonConfigEnabled"}, |
| 202 | {1274, nullptr, "SetDefaultButtonConfig"}, | 202 | {1274, nullptr, "SetDefaultButtonConfig"}, |
| @@ -555,6 +555,16 @@ void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) { | |||
| 555 | rb.Push(ResultSuccess); | 555 | rb.Push(ResultSuccess); |
| 556 | } | 556 | } |
| 557 | 557 | ||
| 558 | void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) { | ||
| 559 | const bool is_attached = true; | ||
| 560 | |||
| 561 | LOG_DEBUG(Service_HID, "(STUBBED) called, is_attached={}", is_attached); | ||
| 562 | |||
| 563 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 564 | rb.Push(ResultSuccess); | ||
| 565 | rb.Push(is_attached); | ||
| 566 | } | ||
| 567 | |||
| 558 | void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) { | 568 | void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) { |
| 559 | LOG_INFO(Service_AM, "(STUBBED) called"); | 569 | LOG_INFO(Service_AM, "(STUBBED) called"); |
| 560 | 570 | ||
| @@ -641,6 +651,34 @@ void IHidSystemServer::InitializeFirmwareUpdate(HLERequestContext& ctx) { | |||
| 641 | rb.Push(ResultSuccess); | 651 | rb.Push(ResultSuccess); |
| 642 | } | 652 | } |
| 643 | 653 | ||
| 654 | void IHidSystemServer::CheckFirmwareUpdateRequired(HLERequestContext& ctx) { | ||
| 655 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 656 | |||
| 657 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 658 | rb.Push(ResultSuccess); | ||
| 659 | } | ||
| 660 | |||
| 661 | void IHidSystemServer::SetFirmwareHotfixUpdateSkipEnabled(HLERequestContext& ctx) { | ||
| 662 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 663 | |||
| 664 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 665 | rb.Push(ResultSuccess); | ||
| 666 | } | ||
| 667 | |||
| 668 | void IHidSystemServer::InitializeUsbFirmwareUpdate(HLERequestContext& ctx) { | ||
| 669 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 670 | |||
| 671 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 672 | rb.Push(ResultSuccess); | ||
| 673 | } | ||
| 674 | |||
| 675 | void IHidSystemServer::FinalizeUsbFirmwareUpdate(HLERequestContext& ctx) { | ||
| 676 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 677 | |||
| 678 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 679 | rb.Push(ResultSuccess); | ||
| 680 | } | ||
| 681 | |||
| 644 | void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) { | 682 | void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) { |
| 645 | LOG_WARNING(Service_HID, "(STUBBED) called"); | 683 | LOG_WARNING(Service_HID, "(STUBBED) called"); |
| 646 | 684 | ||
| @@ -665,6 +703,16 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx | |||
| 665 | rb.PushRaw(touchscreen_config); | 703 | rb.PushRaw(touchscreen_config); |
| 666 | } | 704 | } |
| 667 | 705 | ||
| 706 | void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) { | ||
| 707 | const bool is_enabled = false; | ||
| 708 | |||
| 709 | LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled); | ||
| 710 | |||
| 711 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 712 | rb.Push(ResultSuccess); | ||
| 713 | rb.Push(is_enabled); | ||
| 714 | } | ||
| 715 | |||
| 668 | std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() { | 716 | std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() { |
| 669 | resource_manager->Initialize(); | 717 | resource_manager->Initialize(); |
| 670 | return resource_manager; | 718 | return resource_manager; |
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h index 1e623dfc2..f467e2aa8 100644 --- a/src/core/hle/service/hid/hid_system_server.h +++ b/src/core/hle/service/hid/hid_system_server.h | |||
| @@ -44,6 +44,7 @@ private: | |||
| 44 | void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); | 44 | void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); |
| 45 | void EnableAppletToGetPadInput(HLERequestContext& ctx); | 45 | void EnableAppletToGetPadInput(HLERequestContext& ctx); |
| 46 | void EnableAppletToGetTouchScreen(HLERequestContext& ctx); | 46 | void EnableAppletToGetTouchScreen(HLERequestContext& ctx); |
| 47 | void IsJoyConAttachedOnAllRail(HLERequestContext& ctx); | ||
| 47 | void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); | 48 | void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); |
| 48 | void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); | 49 | void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); |
| 49 | void GetRegisteredDevices(HLERequestContext& ctx); | 50 | void GetRegisteredDevices(HLERequestContext& ctx); |
| @@ -53,8 +54,13 @@ private: | |||
| 53 | void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx); | 54 | void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx); |
| 54 | void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx); | 55 | void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx); |
| 55 | void InitializeFirmwareUpdate(HLERequestContext& ctx); | 56 | void InitializeFirmwareUpdate(HLERequestContext& ctx); |
| 57 | void CheckFirmwareUpdateRequired(HLERequestContext& ctx); | ||
| 58 | void SetFirmwareHotfixUpdateSkipEnabled(HLERequestContext& ctx); | ||
| 59 | void InitializeUsbFirmwareUpdate(HLERequestContext& ctx); | ||
| 60 | void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx); | ||
| 56 | void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); | 61 | void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx); |
| 57 | void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); | 62 | void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx); |
| 63 | void IsUsingCustomButtonConfig(HLERequestContext& ctx); | ||
| 58 | 64 | ||
| 59 | std::shared_ptr<ResourceManager> GetResourceManager(); | 65 | std::shared_ptr<ResourceManager> GetResourceManager(); |
| 60 | 66 | ||
diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp index 17dacef6e..2c5fe6d51 100644 --- a/src/hid_core/resource_manager.cpp +++ b/src/hid_core/resource_manager.cpp | |||
| @@ -224,6 +224,7 @@ Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) | |||
| 224 | void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { | 224 | void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { |
| 225 | std::scoped_lock lock{shared_mutex}; | 225 | std::scoped_lock lock{shared_mutex}; |
| 226 | applet_resource->UnregisterAppletResourceUserId(aruid); | 226 | applet_resource->UnregisterAppletResourceUserId(aruid); |
| 227 | npad->UnregisterAppletResourceUserId(aruid); | ||
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { | 230 | Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { |
diff --git a/src/hid_core/resources/applet_resource.cpp b/src/hid_core/resources/applet_resource.cpp index d16cff1a4..d09a525c6 100644 --- a/src/hid_core/resources/applet_resource.cpp +++ b/src/hid_core/resources/applet_resource.cpp | |||
| @@ -87,7 +87,9 @@ Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input | |||
| 87 | data_index = i; | 87 | data_index = i; |
| 88 | break; | 88 | break; |
| 89 | } | 89 | } |
| 90 | if (registration_list.flag[i] == RegistrationStatus::None) { | 90 | // TODO: Don't Handle pending delete here |
| 91 | if (registration_list.flag[i] == RegistrationStatus::None || | ||
| 92 | registration_list.flag[i] == RegistrationStatus::PendingDelete) { | ||
| 91 | data_index = i; | 93 | data_index = i; |
| 92 | break; | 94 | break; |
| 93 | } | 95 | } |
| @@ -104,30 +106,22 @@ Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input | |||
| 104 | } | 106 | } |
| 105 | 107 | ||
| 106 | void AppletResource::UnregisterAppletResourceUserId(u64 aruid) { | 108 | void AppletResource::UnregisterAppletResourceUserId(u64 aruid) { |
| 107 | u64 index = GetIndexFromAruid(aruid); | 109 | const u64 index = GetIndexFromAruid(aruid); |
| 108 | 110 | ||
| 109 | if (index < AruidIndexMax) { | 111 | if (index >= AruidIndexMax) { |
| 110 | if (data[index].flag.is_assigned) { | 112 | return; |
| 111 | data[index].shared_memory_format = nullptr; | ||
| 112 | data[index].flag.is_assigned.Assign(false); | ||
| 113 | } | ||
| 114 | } | 113 | } |
| 115 | 114 | ||
| 116 | index = GetIndexFromAruid(aruid); | 115 | FreeAppletResourceId(aruid); |
| 117 | if (index < AruidIndexMax) { | 116 | DestroySevenSixAxisTransferMemory(); |
| 118 | DestroySevenSixAxisTransferMemory(); | 117 | data[index].flag.raw = 0; |
| 119 | data[index].flag.raw = 0; | 118 | data[index].aruid = 0; |
| 120 | data[index].aruid = 0; | ||
| 121 | 119 | ||
| 122 | index = GetIndexFromAruid(aruid); | 120 | registration_list.flag[index] = RegistrationStatus::PendingDelete; |
| 123 | if (index < AruidIndexMax) { | ||
| 124 | registration_list.flag[index] = RegistrationStatus::PendingDelete; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | } | 121 | } |
| 128 | 122 | ||
| 129 | void AppletResource::FreeAppletResourceId(u64 aruid) { | 123 | void AppletResource::FreeAppletResourceId(u64 aruid) { |
| 130 | u64 index = GetIndexFromAruid(aruid); | 124 | const u64 index = GetIndexFromAruid(aruid); |
| 131 | if (index >= AruidIndexMax) { | 125 | if (index >= AruidIndexMax) { |
| 132 | return; | 126 | return; |
| 133 | } | 127 | } |
| @@ -144,7 +138,7 @@ u64 AppletResource::GetActiveAruid() { | |||
| 144 | } | 138 | } |
| 145 | 139 | ||
| 146 | Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { | 140 | Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { |
| 147 | u64 index = GetIndexFromAruid(aruid); | 141 | const u64 index = GetIndexFromAruid(aruid); |
| 148 | if (index >= AruidIndexMax) { | 142 | if (index >= AruidIndexMax) { |
| 149 | return ResultAruidNotRegistered; | 143 | return ResultAruidNotRegistered; |
| 150 | } | 144 | } |
| @@ -155,7 +149,7 @@ Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, | |||
| 155 | 149 | ||
| 156 | Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, | 150 | Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, |
| 157 | u64 aruid) { | 151 | u64 aruid) { |
| 158 | u64 index = GetIndexFromAruid(aruid); | 152 | const u64 index = GetIndexFromAruid(aruid); |
| 159 | if (index >= AruidIndexMax) { | 153 | if (index >= AruidIndexMax) { |
| 160 | return ResultAruidNotRegistered; | 154 | return ResultAruidNotRegistered; |
| 161 | } | 155 | } |
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index e6c035628..97f31d26e 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp | |||
| @@ -870,6 +870,11 @@ void NPad::InitializeVibrationDevice( | |||
| 870 | const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid(); | 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); | 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); | 872 | const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index); |
| 873 | |||
| 874 | if (aruid == 0) { | ||
| 875 | return; | ||
| 876 | } | ||
| 877 | |||
| 873 | InitializeVibrationDeviceAtIndex(aruid, npad_index, device_index); | 878 | InitializeVibrationDeviceAtIndex(aruid, npad_index, device_index); |
| 874 | } | 879 | } |
| 875 | 880 | ||
diff --git a/src/hid_core/resources/npad/npad_resource.cpp b/src/hid_core/resources/npad/npad_resource.cpp index b0255a05c..ea9fc14ed 100644 --- a/src/hid_core/resources/npad/npad_resource.cpp +++ b/src/hid_core/resources/npad/npad_resource.cpp | |||
| @@ -46,7 +46,9 @@ Result NPadResource::RegisterAppletResourceUserId(u64 aruid) { | |||
| 46 | data_index = i; | 46 | data_index = i; |
| 47 | break; | 47 | break; |
| 48 | } | 48 | } |
| 49 | if (registration_list.flag[i] == RegistrationStatus::None) { | 49 | // TODO: Don't Handle pending delete here |
| 50 | if (registration_list.flag[i] == RegistrationStatus::None || | ||
| 51 | registration_list.flag[i] == RegistrationStatus::PendingDelete) { | ||
| 50 | data_index = i; | 52 | data_index = i; |
| 51 | break; | 53 | break; |
| 52 | } | 54 | } |