diff options
Diffstat (limited to 'src')
110 files changed, 4184 insertions, 861 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 53aafa08c..06e59d1ac 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -188,8 +188,15 @@ tasks.create<Delete>("ktlintReset") { delete(File(buildDir.path + File.separator + "intermediates/ktLint")) } +val showFormatHelp = { + logger.lifecycle( + "If this check fails, please try running \"gradlew ktlintFormat\" for automatic " + + "codestyle fixes" + ) +} +tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() } +tasks.getByPath("ktlintMainSourceSetCheck").doFirst { showFormatHelp.invoke() } tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset") -tasks.getByPath("preBuild").dependsOn("ktlintCheck") ktlint { version.set("0.47.1") @@ -228,71 +235,33 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") } -fun getGitVersion(): String { - var versionName = "0.0" - - try { - versionName = ProcessBuilder("git", "describe", "--always", "--long") +fun runGitCommand(command: List<String>): String { + return try { + ProcessBuilder(command) .directory(project.rootDir) .redirectOutput(ProcessBuilder.Redirect.PIPE) .redirectError(ProcessBuilder.Redirect.PIPE) .start().inputStream.bufferedReader().use { it.readText() } .trim() - .replace(Regex("(-0)?-[^-]+$"), "") } catch (e: Exception) { - logger.error("Cannot find git, defaulting to dummy version number") + logger.error("Cannot find git") + "" } - - if (System.getenv("GITHUB_ACTIONS") != null) { - val gitTag = System.getenv("GIT_TAG_NAME") - versionName = gitTag ?: versionName - } - - return versionName } -fun getGitHash(): String { - try { - val processBuilder = ProcessBuilder("git", "rev-parse", "--short", "HEAD") - processBuilder.directory(project.rootDir) - val process = processBuilder.start() - val inputStream = process.inputStream - val errorStream = process.errorStream - process.waitFor() - - return if (process.exitValue() == 0) { - inputStream.bufferedReader() - .use { it.readText().trim() } // return the value of gitHash - } else { - val errorMessage = errorStream.bufferedReader().use { it.readText().trim() } - logger.error("Error running git command: $errorMessage") - "dummy-hash" // return a dummy hash value in case of an error - } - } catch (e: Exception) { - logger.error("$e: Cannot find git, defaulting to dummy build hash") - return "dummy-hash" // return a dummy hash value in case of an error +fun getGitVersion(): String { + val versionName = if (System.getenv("GITHUB_ACTIONS") != null) { + val gitTag = System.getenv("GIT_TAG_NAME") ?: "" + gitTag + } else { + runGitCommand(listOf("git", "describe", "--always", "--long")) + .replace(Regex("(-0)?-[^-]+$"), "") } + return versionName.ifEmpty { "0.0" } } -fun getBranch(): String { - try { - val processBuilder = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD") - processBuilder.directory(project.rootDir) - val process = processBuilder.start() - val inputStream = process.inputStream - val errorStream = process.errorStream - process.waitFor() - - return if (process.exitValue() == 0) { - inputStream.bufferedReader() - .use { it.readText().trim() } // return the value of gitHash - } else { - val errorMessage = errorStream.bufferedReader().use { it.readText().trim() } - logger.error("Error running git command: $errorMessage") - "dummy-hash" // return a dummy hash value in case of an error - } - } catch (e: Exception) { - logger.error("$e: Cannot find git, defaulting to dummy build hash") - return "dummy-hash" // return a dummy hash value in case of an error - } -} +fun getGitHash(): String = + runGitCommand(listOf("git", "rev-parse", "--short", "HEAD")).ifEmpty { "dummy-hash" } + +fun getBranch(): String = + runGitCommand(listOf("git", "rev-parse", "--abbrev-ref", "HEAD")).ifEmpty { "dummy-hash" } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt new file mode 100644 index 000000000..f006f9e3d --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.adapters + +import android.annotation.SuppressLint +import androidx.recyclerview.widget.AsyncDifferConfig +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder +import androidx.recyclerview.widget.RecyclerView + +/** + * Generic adapter that implements an [AsyncDifferConfig] and covers some of the basic boilerplate + * code used in every [RecyclerView]. + * Type assigned to [Model] must inherit from [Object] in order to be compared properly. + */ +abstract class AbstractDiffAdapter<Model : Any, Holder : AbstractViewHolder<Model>> : + ListAdapter<Model, Holder>(AsyncDifferConfig.Builder(DiffCallback<Model>()).build()) { + override fun onBindViewHolder(holder: Holder, position: Int) = + holder.bind(currentList[position]) + + private class DiffCallback<Model> : DiffUtil.ItemCallback<Model>() { + override fun areItemsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean { + return oldItem === newItem + } + + @SuppressLint("DiffUtilEquals") + override fun areContentsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean { + return oldItem == newItem + } + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt new file mode 100644 index 000000000..3dfee3d0c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.adapters + +import android.annotation.SuppressLint +import androidx.recyclerview.widget.RecyclerView +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder + +/** + * Generic list class meant to take care of basic lists + * @param currentList The list to show initially + */ +abstract class AbstractListAdapter<Model : Any, Holder : AbstractViewHolder<Model>>( + open var currentList: List<Model> +) : RecyclerView.Adapter<Holder>() { + override fun onBindViewHolder(holder: Holder, position: Int) = + holder.bind(currentList[position]) + + override fun getItemCount(): Int = currentList.size + + /** + * Adds an item to [currentList] and notifies the underlying adapter of the change. If no parameter + * is passed in for position, [item] is added to the end of the list. Invokes [callback] last. + * @param item The item to add to the list + * @param position Index where [item] will be added + * @param callback Lambda that's called at the end of the list changes and has the added list + * position passed in as a parameter + */ + open fun addItem(item: Model, position: Int = -1, callback: ((position: Int) -> Unit)? = null) { + val newList = currentList.toMutableList() + val positionToUpdate: Int + if (position == -1) { + newList.add(item) + currentList = newList + positionToUpdate = currentList.size - 1 + } else { + newList.add(position, item) + currentList = newList + positionToUpdate = position + } + onItemAdded(positionToUpdate, callback) + } + + protected fun onItemAdded(position: Int, callback: ((Int) -> Unit)? = null) { + notifyItemInserted(position) + callback?.invoke(position) + } + + /** + * Replaces the [item] at [position] in the [currentList] and notifies the underlying adapter + * of the change. Invokes [callback] last. + * @param item New list item + * @param position Index where [item] will replace the existing list item + * @param callback Lambda that's called at the end of the list changes and has the changed list + * position passed in as a parameter + */ + fun changeItem(item: Model, position: Int, callback: ((position: Int) -> Unit)? = null) { + val newList = currentList.toMutableList() + newList[position] = item + currentList = newList + onItemChanged(position, callback) + } + + protected fun onItemChanged(position: Int, callback: ((Int) -> Unit)? = null) { + notifyItemChanged(position) + callback?.invoke(position) + } + + /** + * Removes the list item at [position] in [currentList] and notifies the underlying adapter + * of the change. Invokes [callback] last. + * @param position Index where the list item will be removed + * @param callback Lambda that's called at the end of the list changes and has the removed list + * position passed in as a parameter + */ + fun removeItem(position: Int, callback: ((position: Int) -> Unit)? = null) { + val newList = currentList.toMutableList() + newList.removeAt(position) + currentList = newList + onItemRemoved(position, callback) + } + + protected fun onItemRemoved(position: Int, callback: ((Int) -> Unit)? = null) { + notifyItemRemoved(position) + callback?.invoke(position) + } + + /** + * Replaces [currentList] with [newList] and notifies the underlying adapter of the change. + * @param newList The new list to replace [currentList] + */ + @SuppressLint("NotifyDataSetChanged") + open fun replaceList(newList: List<Model>) { + currentList = newList + notifyDataSetChanged() + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt new file mode 100644 index 000000000..52163f9d7 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.adapters + +import org.yuzu.yuzu_emu.model.SelectableItem +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder + +/** + * Generic list class meant to take care of single selection UI updates + * @param currentList The list to show initially + * @param defaultSelection The default selection to use if no list items are selected by + * [SelectableItem.selected] or if the currently selected item is removed from the list + */ +abstract class AbstractSingleSelectionList< + Model : SelectableItem, + Holder : AbstractViewHolder<Model> + >( + final override var currentList: List<Model>, + private val defaultSelection: DefaultSelection = DefaultSelection.Start +) : AbstractListAdapter<Model, Holder>(currentList) { + var selectedItem = getDefaultSelection() + + init { + findSelectedItem() + } + + /** + * Changes the selection state of the [SelectableItem] that was selected and the previously selected + * item and notifies the underlying adapter of the change for those items. Invokes [callback] last. + * Does nothing if [position] is the same as the currently selected item. + * @param position Index of the item that was selected + * @param callback Lambda that's called at the end of the list changes and has the selected list + * position passed in as a parameter + */ + fun selectItem(position: Int, callback: ((position: Int) -> Unit)? = null) { + if (position == selectedItem) { + return + } + + val previouslySelectedItem = selectedItem + selectedItem = position + if (currentList.indices.contains(selectedItem)) { + currentList[selectedItem].onSelectionStateChanged(true) + } + if (currentList.indices.contains(previouslySelectedItem)) { + currentList[previouslySelectedItem].onSelectionStateChanged(false) + } + onItemChanged(previouslySelectedItem) + onItemChanged(selectedItem) + callback?.invoke(position) + } + + /** + * Removes a given item from the list and notifies the underlying adapter of the change. If the + * currently selected item was the item that was removed, the item at the position provided + * by [defaultSelection] will be made the new selection. Invokes [callback] last. + * @param position Index of the item that was removed + * @param callback Lambda that's called at the end of the list changes and has the removed and + * selected list positions passed in as parameters + */ + fun removeSelectableItem( + position: Int, + callback: ((removedPosition: Int, selectedPosition: Int) -> Unit)? + ) { + removeItem(position) + if (position == selectedItem) { + selectedItem = getDefaultSelection() + currentList[selectedItem].onSelectionStateChanged(true) + onItemChanged(selectedItem) + } else if (position < selectedItem) { + selectedItem-- + } + callback?.invoke(position, selectedItem) + } + + override fun addItem(item: Model, position: Int, callback: ((Int) -> Unit)?) { + super.addItem(item, position, callback) + if (position <= selectedItem && position != -1) { + selectedItem++ + } + } + + override fun replaceList(newList: List<Model>) { + super.replaceList(newList) + findSelectedItem() + } + + private fun findSelectedItem() { + for (i in currentList.indices) { + if (currentList[i].selected) { + selectedItem = i + break + } + } + } + + private fun getDefaultSelection(): Int = + when (defaultSelection) { + DefaultSelection.Start -> currentList.indices.first + DefaultSelection.End -> currentList.indices.last + } + + enum class DefaultSelection { Start, End } +} 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 15c7ca3c9..94c151325 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 @@ -5,48 +5,28 @@ package org.yuzu.yuzu_emu.adapters import android.view.LayoutInflater import android.view.ViewGroup -import androidx.recyclerview.widget.AsyncDifferConfig -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding import org.yuzu.yuzu_emu.model.Addon +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder -class AddonAdapter : ListAdapter<Addon, AddonAdapter.AddonViewHolder>( - AsyncDifferConfig.Builder(DiffCallback()).build() -) { +class AddonAdapter : AbstractDiffAdapter<Addon, AddonAdapter.AddonViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder { ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false) .also { return AddonViewHolder(it) } } - override fun getItemCount(): Int = currentList.size - - override fun onBindViewHolder(holder: AddonViewHolder, position: Int) = - holder.bind(currentList[position]) - inner class AddonViewHolder(val binding: ListItemAddonBinding) : - RecyclerView.ViewHolder(binding.root) { - fun bind(addon: Addon) { + AbstractViewHolder<Addon>(binding) { + override fun bind(model: Addon) { binding.root.setOnClickListener { binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked } - binding.title.text = addon.title - binding.version.text = addon.version + binding.title.text = model.title + binding.version.text = model.version binding.addonSwitch.setOnCheckedChangeListener { _, checked -> - addon.enabled = checked + model.enabled = checked } - binding.addonSwitch.isChecked = addon.enabled - } - } - - private class DiffCallback : DiffUtil.ItemCallback<Addon>() { - override fun areItemsTheSame(oldItem: Addon, newItem: Addon): Boolean { - return oldItem == newItem - } - - override fun areContentsTheSame(oldItem: Addon, newItem: Addon): Boolean { - return oldItem == newItem + binding.addonSwitch.isChecked = model.enabled } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt index 4a05c5be9..41d7f72b8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt @@ -4,13 +4,11 @@ package org.yuzu.yuzu_emu.adapters import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.FragmentActivity import androidx.navigation.findNavController -import androidx.recyclerview.widget.RecyclerView import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R @@ -19,72 +17,58 @@ import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding import org.yuzu.yuzu_emu.model.Applet import org.yuzu.yuzu_emu.model.AppletInfo import org.yuzu.yuzu_emu.model.Game +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder -class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) : - RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(), - View.OnClickListener { - +class AppletAdapter(val activity: FragmentActivity, applets: List<Applet>) : + AbstractListAdapter<Applet, AppletAdapter.AppletViewHolder>(applets) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): AppletAdapter.AppletViewHolder { CardSimpleOutlinedBinding.inflate(LayoutInflater.from(parent.context), parent, false) - .apply { root.setOnClickListener(this@AppletAdapter) } .also { return AppletViewHolder(it) } } - override fun onBindViewHolder(holder: AppletViewHolder, position: Int) = - holder.bind(applets[position]) - - override fun getItemCount(): Int = applets.size - - override fun onClick(view: View) { - val applet = (view.tag as AppletViewHolder).applet - val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId) - if (appletPath.isEmpty()) { - Toast.makeText( - YuzuApplication.appContext, - R.string.applets_error_applet, - Toast.LENGTH_SHORT - ).show() - return - } - - if (applet.appletInfo == AppletInfo.Cabinet) { - view.findNavController() - .navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment) - return - } - - NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId) - val appletGame = Game( - title = YuzuApplication.appContext.getString(applet.titleId), - path = appletPath - ) - val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) - view.findNavController().navigate(action) - } - inner class AppletViewHolder(val binding: CardSimpleOutlinedBinding) : - RecyclerView.ViewHolder(binding.root) { - lateinit var applet: Applet - - init { - itemView.tag = this - } - - fun bind(applet: Applet) { - this.applet = applet - - binding.title.setText(applet.titleId) - binding.description.setText(applet.descriptionId) + AbstractViewHolder<Applet>(binding) { + override fun bind(model: Applet) { + binding.title.setText(model.titleId) + binding.description.setText(model.descriptionId) binding.icon.setImageDrawable( ResourcesCompat.getDrawable( binding.icon.context.resources, - applet.iconId, + model.iconId, binding.icon.context.theme ) ) + + binding.root.setOnClickListener { onClick(model) } + } + + fun onClick(applet: Applet) { + val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId) + if (appletPath.isEmpty()) { + Toast.makeText( + binding.root.context, + R.string.applets_error_applet, + Toast.LENGTH_SHORT + ).show() + return + } + + if (applet.appletInfo == AppletInfo.Cabinet) { + binding.root.findNavController() + .navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment) + return + } + + NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId) + val appletGame = Game( + title = YuzuApplication.appContext.getString(applet.titleId), + path = appletPath + ) + val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) + binding.root.findNavController().navigate(action) } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt index e7b7c0f2f..a56137148 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt @@ -4,12 +4,10 @@ package org.yuzu.yuzu_emu.adapters import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController -import androidx.recyclerview.widget.RecyclerView import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R @@ -19,54 +17,43 @@ import org.yuzu.yuzu_emu.model.CabinetMode import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder import org.yuzu.yuzu_emu.model.AppletInfo import org.yuzu.yuzu_emu.model.Game +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder class CabinetLauncherDialogAdapter(val fragment: Fragment) : - RecyclerView.Adapter<CabinetModeViewHolder>(), - View.OnClickListener { - private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size) + AbstractListAdapter<CabinetMode, CabinetModeViewHolder>( + CabinetMode.values().copyOfRange(1, CabinetMode.entries.size).toList() + ) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder { DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) - .apply { root.setOnClickListener(this@CabinetLauncherDialogAdapter) } .also { return CabinetModeViewHolder(it) } } - override fun getItemCount(): Int = cabinetModes.size - - override fun onBindViewHolder(holder: CabinetModeViewHolder, position: Int) = - holder.bind(cabinetModes[position]) - - override fun onClick(view: View) { - val mode = (view.tag as CabinetModeViewHolder).cabinetMode - val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId) - NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId) - NativeLibrary.setCabinetMode(mode.id) - val appletGame = Game( - title = YuzuApplication.appContext.getString(R.string.cabinet_applet), - path = appletPath - ) - val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) - fragment.findNavController().navigate(action) - } - inner class CabinetModeViewHolder(val binding: DialogListItemBinding) : - RecyclerView.ViewHolder(binding.root) { - lateinit var cabinetMode: CabinetMode - - init { - itemView.tag = this - } - - fun bind(cabinetMode: CabinetMode) { - this.cabinetMode = cabinetMode + AbstractViewHolder<CabinetMode>(binding) { + override fun bind(model: CabinetMode) { binding.icon.setImageDrawable( ResourcesCompat.getDrawable( binding.icon.context.resources, - cabinetMode.iconId, + model.iconId, binding.icon.context.theme ) ) - binding.title.setText(cabinetMode.titleId) + binding.title.setText(model.titleId) + + binding.root.setOnClickListener { onClick(model) } + } + + private fun onClick(mode: CabinetMode) { + val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId) + NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId) + NativeLibrary.setCabinetMode(mode.id) + val appletGame = Game( + title = YuzuApplication.appContext.getString(R.string.cabinet_applet), + path = appletPath + ) + val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame) + fragment.findNavController().navigate(action) } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt index d290a656c..d6f17cf29 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt @@ -7,65 +7,39 @@ import android.text.TextUtils import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.recyclerview.widget.AsyncDifferConfig -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding +import org.yuzu.yuzu_emu.features.settings.model.StringSetting +import org.yuzu.yuzu_emu.model.Driver import org.yuzu.yuzu_emu.model.DriverViewModel -import org.yuzu.yuzu_emu.utils.GpuDriverHelper -import org.yuzu.yuzu_emu.utils.GpuDriverMetadata +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder class DriverAdapter(private val driverViewModel: DriverViewModel) : - ListAdapter<Pair<String, GpuDriverMetadata>, DriverAdapter.DriverViewHolder>( - AsyncDifferConfig.Builder(DiffCallback()).build() + AbstractSingleSelectionList<Driver, DriverAdapter.DriverViewHolder>( + driverViewModel.driverList.value ) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder { - val binding = - CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return DriverViewHolder(binding) - } - - override fun getItemCount(): Int = currentList.size - - override fun onBindViewHolder(holder: DriverViewHolder, position: Int) = - holder.bind(currentList[position]) - - private fun onSelectDriver(position: Int) { - driverViewModel.setSelectedDriverIndex(position) - notifyItemChanged(driverViewModel.previouslySelectedDriver) - notifyItemChanged(driverViewModel.selectedDriver) - } - - private fun onDeleteDriver(driverData: Pair<String, GpuDriverMetadata>, position: Int) { - if (driverViewModel.selectedDriver > position) { - driverViewModel.setSelectedDriverIndex(driverViewModel.selectedDriver - 1) - } - if (GpuDriverHelper.customDriverSettingData == driverData.second) { - driverViewModel.setSelectedDriverIndex(0) - } - driverViewModel.driversToDelete.add(driverData.first) - driverViewModel.removeDriver(driverData) - notifyItemRemoved(position) - notifyItemChanged(driverViewModel.selectedDriver) + CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) + .also { return DriverViewHolder(it) } } inner class DriverViewHolder(val binding: CardDriverOptionBinding) : - RecyclerView.ViewHolder(binding.root) { - private lateinit var driverData: Pair<String, GpuDriverMetadata> - - fun bind(driverData: Pair<String, GpuDriverMetadata>) { - this.driverData = driverData - val driver = driverData.second - + AbstractViewHolder<Driver>(binding) { + override fun bind(model: Driver) { binding.apply { - radioButton.isChecked = driverViewModel.selectedDriver == bindingAdapterPosition + radioButton.isChecked = model.selected root.setOnClickListener { - onSelectDriver(bindingAdapterPosition) + selectItem(bindingAdapterPosition) { + driverViewModel.onDriverSelected(it) + driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) + } } buttonDelete.setOnClickListener { - onDeleteDriver(driverData, bindingAdapterPosition) + removeSelectableItem( + bindingAdapterPosition + ) { removedPosition: Int, selectedPosition: Int -> + driverViewModel.onDriverRemoved(removedPosition, selectedPosition) + driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) + } } // Delay marquee by 3s @@ -80,38 +54,19 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) : }, 3000 ) - if (driver.name == null) { - title.setText(R.string.system_gpu_driver) - description.text = "" - version.text = "" - version.visibility = View.GONE - description.visibility = View.GONE - buttonDelete.visibility = View.GONE - } else { - title.text = driver.name - version.text = driver.version - description.text = driver.description + title.text = model.title + version.text = model.version + description.text = model.description + if (model.description.isNotEmpty()) { version.visibility = View.VISIBLE description.visibility = View.VISIBLE buttonDelete.visibility = View.VISIBLE + } else { + version.visibility = View.GONE + description.visibility = View.GONE + buttonDelete.visibility = View.GONE } } } } - - private class DiffCallback : DiffUtil.ItemCallback<Pair<String, GpuDriverMetadata>>() { - override fun areItemsTheSame( - oldItem: Pair<String, GpuDriverMetadata>, - newItem: Pair<String, GpuDriverMetadata> - ): Boolean { - return oldItem.first == newItem.first - } - - override fun areContentsTheSame( - oldItem: Pair<String, GpuDriverMetadata>, - newItem: Pair<String, GpuDriverMetadata> - ): Boolean { - return oldItem.second == newItem.second - } - } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt index ab657a7b9..3d8f0bda8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt @@ -8,19 +8,14 @@ import android.text.TextUtils import android.view.LayoutInflater import android.view.ViewGroup import androidx.fragment.app.FragmentActivity -import androidx.recyclerview.widget.AsyncDifferConfig -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView import org.yuzu.yuzu_emu.databinding.CardFolderBinding import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment import org.yuzu.yuzu_emu.model.GameDir import org.yuzu.yuzu_emu.model.GamesViewModel +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : - ListAdapter<GameDir, FolderAdapter.FolderViewHolder>( - AsyncDifferConfig.Builder(DiffCallback()).build() - ) { + AbstractDiffAdapter<GameDir, FolderAdapter.FolderViewHolder>() { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int @@ -29,18 +24,11 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie .also { return FolderViewHolder(it) } } - override fun onBindViewHolder(holder: FolderAdapter.FolderViewHolder, position: Int) = - holder.bind(currentList[position]) - inner class FolderViewHolder(val binding: CardFolderBinding) : - RecyclerView.ViewHolder(binding.root) { - private lateinit var gameDir: GameDir - - fun bind(gameDir: GameDir) { - this.gameDir = gameDir - + AbstractViewHolder<GameDir>(binding) { + override fun bind(model: GameDir) { binding.apply { - path.text = Uri.parse(gameDir.uriString).path + path.text = Uri.parse(model.uriString).path path.postDelayed( { path.isSelected = true @@ -50,7 +38,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie ) buttonEdit.setOnClickListener { - GameFolderPropertiesDialogFragment.newInstance(this@FolderViewHolder.gameDir) + GameFolderPropertiesDialogFragment.newInstance(model) .show( activity.supportFragmentManager, GameFolderPropertiesDialogFragment.TAG @@ -58,19 +46,9 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie } buttonDelete.setOnClickListener { - gamesViewModel.removeFolder(this@FolderViewHolder.gameDir) + gamesViewModel.removeFolder(model) } } } } - - private class DiffCallback : DiffUtil.ItemCallback<GameDir>() { - override fun areItemsTheSame(oldItem: GameDir, newItem: GameDir): Boolean { - return oldItem == newItem - } - - override fun areContentsTheSame(oldItem: GameDir, newItem: GameDir): Boolean { - return oldItem == newItem - } - } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index a578f0de8..e26c2e0ab 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -9,7 +9,6 @@ import android.graphics.drawable.LayerDrawable import android.net.Uri import android.text.TextUtils import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.Toast @@ -25,10 +24,6 @@ import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.navigation.findNavController import androidx.preference.PreferenceManager -import androidx.recyclerview.widget.AsyncDifferConfig -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -36,122 +31,26 @@ import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.activities.EmulationActivity -import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder import org.yuzu.yuzu_emu.databinding.CardGameBinding import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.utils.GameIconUtils +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder class GameAdapter(private val activity: AppCompatActivity) : - ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()), - View.OnClickListener, - View.OnLongClickListener { + AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder { - // Create a new view. - val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) - binding.cardGame.setOnClickListener(this) - binding.cardGame.setOnLongClickListener(this) - - // Use that view to create a ViewHolder. - return GameViewHolder(binding) - } - - override fun onBindViewHolder(holder: GameViewHolder, position: Int) = - holder.bind(currentList[position]) - - override fun getItemCount(): Int = currentList.size - - /** - * Launches the game that was clicked on. - * - * @param view The card representing the game the user wants to play. - */ - override fun onClick(view: View) { - val holder = view.tag as GameViewHolder - - val gameExists = DocumentFile.fromSingleUri( - YuzuApplication.appContext, - Uri.parse(holder.game.path) - )?.exists() == true - if (!gameExists) { - Toast.makeText( - YuzuApplication.appContext, - R.string.loader_error_file_not_found, - Toast.LENGTH_LONG - ).show() - - ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true) - return - } - - val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) - preferences.edit() - .putLong( - holder.game.keyLastPlayedTime, - System.currentTimeMillis() - ) - .apply() - - val openIntent = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply { - action = Intent.ACTION_VIEW - data = Uri.parse(holder.game.path) - } - - activity.lifecycleScope.launch { - withContext(Dispatchers.IO) { - val layerDrawable = ResourcesCompat.getDrawable( - YuzuApplication.appContext.resources, - R.drawable.shortcut, - null - ) as LayerDrawable - layerDrawable.setDrawableByLayerId( - R.id.shortcut_foreground, - GameIconUtils.getGameIcon(activity, holder.game) - .toDrawable(YuzuApplication.appContext.resources) - ) - val inset = YuzuApplication.appContext.resources - .getDimensionPixelSize(R.dimen.icon_inset) - layerDrawable.setLayerInset(1, inset, inset, inset, inset) - val shortcut = - ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path) - .setShortLabel(holder.game.title) - .setIcon( - IconCompat.createWithAdaptiveBitmap( - layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888) - ) - ) - .setIntent(openIntent) - .build() - ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) - } - } - - val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game, true) - view.findNavController().navigate(action) - } - - override fun onLongClick(view: View): Boolean { - val holder = view.tag as GameViewHolder - val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(holder.game) - view.findNavController().navigate(action) - return true + CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) + .also { return GameViewHolder(it) } } inner class GameViewHolder(val binding: CardGameBinding) : - RecyclerView.ViewHolder(binding.root) { - lateinit var game: Game - - init { - binding.cardGame.tag = this - } - - fun bind(game: Game) { - this.game = game - + AbstractViewHolder<Game>(binding) { + override fun bind(model: Game) { binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP - GameIconUtils.loadGameIcon(game, binding.imageGameScreen) + GameIconUtils.loadGameIcon(model, binding.imageGameScreen) - binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ") + binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ") binding.textGameTitle.postDelayed( { @@ -160,16 +59,79 @@ class GameAdapter(private val activity: AppCompatActivity) : }, 3000 ) + + binding.cardGame.setOnClickListener { onClick(model) } + binding.cardGame.setOnLongClickListener { onLongClick(model) } } - } - private class DiffCallback : DiffUtil.ItemCallback<Game>() { - override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean { - return oldItem == newItem + fun onClick(game: Game) { + val gameExists = DocumentFile.fromSingleUri( + YuzuApplication.appContext, + Uri.parse(game.path) + )?.exists() == true + if (!gameExists) { + Toast.makeText( + YuzuApplication.appContext, + R.string.loader_error_file_not_found, + Toast.LENGTH_LONG + ).show() + + ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true) + return + } + + val preferences = + PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) + preferences.edit() + .putLong( + game.keyLastPlayedTime, + System.currentTimeMillis() + ) + .apply() + + val openIntent = + Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply { + action = Intent.ACTION_VIEW + data = Uri.parse(game.path) + } + + activity.lifecycleScope.launch { + withContext(Dispatchers.IO) { + val layerDrawable = ResourcesCompat.getDrawable( + YuzuApplication.appContext.resources, + R.drawable.shortcut, + null + ) as LayerDrawable + layerDrawable.setDrawableByLayerId( + R.id.shortcut_foreground, + GameIconUtils.getGameIcon(activity, game) + .toDrawable(YuzuApplication.appContext.resources) + ) + val inset = YuzuApplication.appContext.resources + .getDimensionPixelSize(R.dimen.icon_inset) + layerDrawable.setLayerInset(1, inset, inset, inset, inset) + val shortcut = + ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path) + .setShortLabel(game.title) + .setIcon( + IconCompat.createWithAdaptiveBitmap( + layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888) + ) + ) + .setIntent(openIntent) + .build() + ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) + } + } + + val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true) + binding.root.findNavController().navigate(action) } - override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { - return oldItem == newItem + fun onLongClick(game: Game): Boolean { + val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game) + binding.root.findNavController().navigate(action) + return true } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt index 95841d786..0046d5314 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt @@ -12,23 +12,22 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.launch import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding import org.yuzu.yuzu_emu.model.GameProperty import org.yuzu.yuzu_emu.model.InstallableProperty import org.yuzu.yuzu_emu.model.SubmenuProperty +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder class GamePropertiesAdapter( private val viewLifecycle: LifecycleOwner, private var properties: List<GameProperty> -) : - RecyclerView.Adapter<GamePropertiesAdapter.GamePropertyViewHolder>() { +) : AbstractListAdapter<GameProperty, AbstractViewHolder<GameProperty>>(properties) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int - ): GamePropertyViewHolder { + ): AbstractViewHolder<GameProperty> { val inflater = LayoutInflater.from(parent.context) return when (viewType) { PropertyType.Submenu.ordinal -> { @@ -51,11 +50,6 @@ class GamePropertiesAdapter( } } - override fun getItemCount(): Int = properties.size - - override fun onBindViewHolder(holder: GamePropertyViewHolder, position: Int) = - holder.bind(properties[position]) - override fun getItemViewType(position: Int): Int { return when (properties[position]) { is SubmenuProperty -> PropertyType.Submenu.ordinal @@ -63,14 +57,10 @@ class GamePropertiesAdapter( } } - sealed class GamePropertyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - abstract fun bind(property: GameProperty) - } - inner class SubmenuPropertyViewHolder(val binding: CardSimpleOutlinedBinding) : - GamePropertyViewHolder(binding.root) { - override fun bind(property: GameProperty) { - val submenuProperty = property as SubmenuProperty + AbstractViewHolder<GameProperty>(binding) { + override fun bind(model: GameProperty) { + val submenuProperty = model as SubmenuProperty binding.root.setOnClickListener { submenuProperty.action.invoke() @@ -108,9 +98,9 @@ class GamePropertiesAdapter( } inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) : - GamePropertyViewHolder(binding.root) { - override fun bind(property: GameProperty) { - val installableProperty = property as InstallableProperty + AbstractViewHolder<GameProperty>(binding) { + override fun bind(model: GameProperty) { + val installableProperty = model as InstallableProperty binding.title.setText(installableProperty.titleId) binding.description.setText(installableProperty.descriptionId) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt index 58ce343f4..b512845d5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt @@ -14,69 +14,37 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.launch import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.model.HomeSetting +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder class HomeSettingAdapter( private val activity: AppCompatActivity, private val viewLifecycle: LifecycleOwner, - var options: List<HomeSetting> -) : - RecyclerView.Adapter<HomeSettingAdapter.HomeOptionViewHolder>(), - View.OnClickListener { + options: List<HomeSetting> +) : AbstractListAdapter<HomeSetting, HomeSettingAdapter.HomeOptionViewHolder>(options) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder { - val binding = - CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) - binding.root.setOnClickListener(this) - return HomeOptionViewHolder(binding) - } - - override fun getItemCount(): Int { - return options.size - } - - override fun onBindViewHolder(holder: HomeOptionViewHolder, position: Int) { - holder.bind(options[position]) - } - - override fun onClick(view: View) { - val holder = view.tag as HomeOptionViewHolder - if (holder.option.isEnabled.invoke()) { - holder.option.onClick.invoke() - } else { - MessageDialogFragment.newInstance( - activity, - titleId = holder.option.disabledTitleId, - descriptionId = holder.option.disabledMessageId - ).show(activity.supportFragmentManager, MessageDialogFragment.TAG) - } + CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) + .also { return HomeOptionViewHolder(it) } } inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) : - RecyclerView.ViewHolder(binding.root) { - lateinit var option: HomeSetting - - init { - itemView.tag = this - } - - fun bind(option: HomeSetting) { - this.option = option - binding.optionTitle.text = activity.resources.getString(option.titleId) - binding.optionDescription.text = activity.resources.getString(option.descriptionId) + AbstractViewHolder<HomeSetting>(binding) { + override fun bind(model: HomeSetting) { + binding.optionTitle.text = activity.resources.getString(model.titleId) + binding.optionDescription.text = activity.resources.getString(model.descriptionId) binding.optionIcon.setImageDrawable( ResourcesCompat.getDrawable( activity.resources, - option.iconId, + model.iconId, activity.theme ) ) - when (option.titleId) { + when (model.titleId) { R.string.get_early_access -> binding.optionLayout.background = ContextCompat.getDrawable( @@ -85,7 +53,7 @@ class HomeSettingAdapter( ) } - if (!option.isEnabled.invoke()) { + if (!model.isEnabled.invoke()) { binding.optionTitle.alpha = 0.5f binding.optionDescription.alpha = 0.5f binding.optionIcon.alpha = 0.5f @@ -93,7 +61,7 @@ class HomeSettingAdapter( viewLifecycle.lifecycleScope.launch { viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) { - option.details.collect { updateOptionDetails(it) } + model.details.collect { updateOptionDetails(it) } } } binding.optionDetail.postDelayed( @@ -103,6 +71,20 @@ class HomeSettingAdapter( }, 3000 ) + + binding.root.setOnClickListener { onClick(model) } + } + + private fun onClick(model: HomeSetting) { + if (model.isEnabled.invoke()) { + model.onClick.invoke() + } else { + MessageDialogFragment.newInstance( + activity, + titleId = model.disabledTitleId, + descriptionId = model.disabledMessageId + ).show(activity.supportFragmentManager, MessageDialogFragment.TAG) + } } private fun updateOptionDetails(detailString: String) { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt index e960fbaab..4218c4e52 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt @@ -6,43 +6,33 @@ package org.yuzu.yuzu_emu.adapters import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView import org.yuzu.yuzu_emu.databinding.CardInstallableBinding import org.yuzu.yuzu_emu.model.Installable +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder -class InstallableAdapter(private val installables: List<Installable>) : - RecyclerView.Adapter<InstallableAdapter.InstallableViewHolder>() { +class InstallableAdapter(installables: List<Installable>) : + AbstractListAdapter<Installable, InstallableAdapter.InstallableViewHolder>(installables) { override fun onCreateViewHolder( parent: ViewGroup, viewType: Int ): InstallableAdapter.InstallableViewHolder { - val binding = - CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return InstallableViewHolder(binding) + CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false) + .also { return InstallableViewHolder(it) } } - override fun getItemCount(): Int = installables.size - - override fun onBindViewHolder(holder: InstallableAdapter.InstallableViewHolder, position: Int) = - holder.bind(installables[position]) - inner class InstallableViewHolder(val binding: CardInstallableBinding) : - RecyclerView.ViewHolder(binding.root) { - lateinit var installable: Installable - - fun bind(installable: Installable) { - this.installable = installable - - binding.title.setText(installable.titleId) - binding.description.setText(installable.descriptionId) + AbstractViewHolder<Installable>(binding) { + override fun bind(model: Installable) { + binding.title.setText(model.titleId) + binding.description.setText(model.descriptionId) - if (installable.install != null) { + if (model.install != null) { binding.buttonInstall.visibility = View.VISIBLE - binding.buttonInstall.setOnClickListener { installable.install.invoke() } + binding.buttonInstall.setOnClickListener { model.install.invoke() } } - if (installable.export != null) { + if (model.export != null) { binding.buttonExport.visibility = View.VISIBLE - binding.buttonExport.setOnClickListener { installable.export.invoke() } + binding.buttonExport.setOnClickListener { model.export.invoke() } } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt index bc6ff1364..38bb1f96f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt @@ -7,49 +7,33 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.RecyclerView.ViewHolder -import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment import org.yuzu.yuzu_emu.model.License +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder -class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) : - RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(), - View.OnClickListener { +class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) : + AbstractListAdapter<License, LicenseAdapter.LicenseViewHolder>(licenses) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder { - val binding = - ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false) - binding.root.setOnClickListener(this) - return LicenseViewHolder(binding) + ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false) + .also { return LicenseViewHolder(it) } } - override fun getItemCount(): Int = licenses.size + inner class LicenseViewHolder(val binding: ListItemSettingBinding) : + AbstractViewHolder<License>(binding) { + override fun bind(model: License) { + binding.apply { + textSettingName.text = root.context.getString(model.titleId) + textSettingDescription.text = root.context.getString(model.descriptionId) + textSettingValue.visibility = View.GONE - override fun onBindViewHolder(holder: LicenseViewHolder, position: Int) { - holder.bind(licenses[position]) - } - - override fun onClick(view: View) { - val license = (view.tag as LicenseViewHolder).license - LicenseBottomSheetDialogFragment.newInstance(license) - .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG) - } - - inner class LicenseViewHolder(val binding: ListItemSettingBinding) : ViewHolder(binding.root) { - lateinit var license: License - - init { - itemView.tag = this + root.setOnClickListener { onClick(model) } + } } - fun bind(license: License) { - this.license = license - - val context = YuzuApplication.appContext - binding.textSettingName.text = context.getString(license.titleId) - binding.textSettingDescription.text = context.getString(license.descriptionId) - binding.textSettingValue.visibility = View.GONE + private fun onClick(license: License) { + LicenseBottomSheetDialogFragment.newInstance(license) + .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG) } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt index 6b46d359e..02118e1a8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt @@ -10,7 +10,6 @@ import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.core.content.res.ResourcesCompat import androidx.lifecycle.ViewModelProvider -import androidx.recyclerview.widget.RecyclerView import com.google.android.material.button.MaterialButton import org.yuzu.yuzu_emu.databinding.PageSetupBinding import org.yuzu.yuzu_emu.model.HomeViewModel @@ -18,31 +17,19 @@ import org.yuzu.yuzu_emu.model.SetupCallback import org.yuzu.yuzu_emu.model.SetupPage import org.yuzu.yuzu_emu.model.StepState import org.yuzu.yuzu_emu.utils.ViewUtils +import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder -class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) : - RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() { +class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) : + AbstractListAdapter<SetupPage, SetupAdapter.SetupPageViewHolder>(pages) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder { - val binding = PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return SetupPageViewHolder(binding) + PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false) + .also { return SetupPageViewHolder(it) } } - override fun getItemCount(): Int = pages.size - - override fun onBindViewHolder(holder: SetupPageViewHolder, position: Int) = - holder.bind(pages[position]) - inner class SetupPageViewHolder(val binding: PageSetupBinding) : - RecyclerView.ViewHolder(binding.root), SetupCallback { - lateinit var page: SetupPage - - init { - itemView.tag = this - } - - fun bind(page: SetupPage) { - this.page = page - - if (page.stepCompleted.invoke() == StepState.COMPLETE) { + AbstractViewHolder<SetupPage>(binding), SetupCallback { + override fun bind(model: SetupPage) { + if (model.stepCompleted.invoke() == StepState.COMPLETE) { binding.buttonAction.visibility = View.INVISIBLE binding.textConfirmation.visibility = View.VISIBLE } @@ -50,31 +37,31 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) binding.icon.setImageDrawable( ResourcesCompat.getDrawable( activity.resources, - page.iconId, + model.iconId, activity.theme ) ) - binding.textTitle.text = activity.resources.getString(page.titleId) + binding.textTitle.text = activity.resources.getString(model.titleId) binding.textDescription.text = - Html.fromHtml(activity.resources.getString(page.descriptionId), 0) + Html.fromHtml(activity.resources.getString(model.descriptionId), 0) binding.buttonAction.apply { - text = activity.resources.getString(page.buttonTextId) - if (page.buttonIconId != 0) { + text = activity.resources.getString(model.buttonTextId) + if (model.buttonIconId != 0) { icon = ResourcesCompat.getDrawable( activity.resources, - page.buttonIconId, + model.buttonIconId, activity.theme ) } iconGravity = - if (page.leftAlignedIcon) { + if (model.leftAlignedIcon) { MaterialButton.ICON_GRAVITY_START } else { MaterialButton.ICON_GRAVITY_END } setOnClickListener { - page.buttonAction.invoke(this@SetupPageViewHolder) + model.buttonAction.invoke(this@SetupPageViewHolder) } } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt index a1620fbb7..5b5f800c1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt @@ -76,8 +76,8 @@ class AboutFragment : Fragment() { binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment) } - binding.textBuildHash.text = BuildConfig.GIT_HASH - binding.buttonBuildHash.setOnClickListener { + binding.textVersionName.text = BuildConfig.VERSION_NAME + binding.textVersionName.setOnClickListener { val clipBoard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH) 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 cc71254dc..9dabb9c41 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 @@ -3,6 +3,7 @@ package org.yuzu.yuzu_emu.fragments +import android.annotation.SuppressLint import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -13,20 +14,26 @@ import androidx.core.view.WindowInsetsCompat import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.transition.MaterialSharedAxis -import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.adapters.DriverAdapter import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding +import org.yuzu.yuzu_emu.features.settings.model.StringSetting +import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.GpuDriverHelper +import org.yuzu.yuzu_emu.utils.NativeConfig import java.io.File import java.io.IOException @@ -55,12 +62,43 @@ class DriverManagerFragment : Fragment() { return binding.root } + // This is using the correct scope, lint is just acting up + @SuppressLint("UnsafeRepeatOnLifecycleDetector") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) homeViewModel.setNavigationVisibility(visible = false, animated = true) homeViewModel.setStatusBarShadeVisibility(visible = false) driverViewModel.onOpenDriverManager(args.game) + if (NativeConfig.isPerGameConfigLoaded()) { + binding.toolbarDrivers.inflateMenu(R.menu.menu_driver_manager) + driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) + binding.toolbarDrivers.setOnMenuItemClickListener { + when (it.itemId) { + R.id.menu_driver_clear -> { + StringSetting.DRIVER_PATH.global = true + driverViewModel.updateDriverList() + (binding.listDrivers.adapter as DriverAdapter) + .replaceList(driverViewModel.driverList.value) + driverViewModel.showClearButton(false) + true + } + + else -> false + } + } + + viewLifecycleOwner.lifecycleScope.apply { + launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + driverViewModel.showClearButton.collect { + binding.toolbarDrivers.menu + .findItem(R.id.menu_driver_clear).isVisible = it + } + } + } + } + } if (!driverViewModel.isInteractionAllowed.value) { DriversLoadingDialogFragment().show( @@ -85,25 +123,6 @@ class DriverManagerFragment : Fragment() { adapter = DriverAdapter(driverViewModel) } - viewLifecycleOwner.lifecycleScope.apply { - launch { - driverViewModel.driverList.collectLatest { - (binding.listDrivers.adapter as DriverAdapter).submitList(it) - } - } - launch { - driverViewModel.newDriverInstalled.collect { - if (_binding != null && it) { - (binding.listDrivers.adapter as DriverAdapter).apply { - notifyItemChanged(driverViewModel.previouslySelectedDriver) - notifyItemChanged(driverViewModel.selectedDriver) - driverViewModel.setNewDriverInstalled(false) - } - } - } - } - } - setInsets() } @@ -160,7 +179,7 @@ class DriverManagerFragment : Fragment() { false ) { val driverPath = - "${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}" + "${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(result)}" val driverFile = File(driverPath) // Ignore file exceptions when a user selects an invalid zip @@ -177,12 +196,21 @@ class DriverManagerFragment : Fragment() { val driverData = GpuDriverHelper.getMetadataFromZip(driverFile) val driverInList = - driverViewModel.driverList.value.firstOrNull { it.second == driverData } + driverViewModel.driverData.firstOrNull { it.second == driverData } if (driverInList != null) { return@newInstance getString(R.string.driver_already_installed) } else { - driverViewModel.addDriver(Pair(driverPath, driverData)) - driverViewModel.setNewDriverInstalled(true) + driverViewModel.onDriverAdded(Pair(driverPath, driverData)) + withContext(Dispatchers.Main) { + if (_binding != null) { + val adapter = binding.listDrivers.adapter as DriverAdapter + adapter.addItem(driverData.toDriver()) + adapter.selectItem(adapter.currentList.indices.last) + driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global) + binding.listDrivers + .smoothScrollToPosition(adapter.currentList.indices.last) + } + } } return@newInstance Any() }.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt new file mode 100644 index 000000000..de342212a --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.model + +import org.yuzu.yuzu_emu.utils.GpuDriverMetadata + +data class Driver( + override var selected: Boolean, + val title: String, + val version: String = "", + val description: String = "" +) : SelectableItem { + override fun onSelectionStateChanged(selected: Boolean) { + this.selected = selected + } + + companion object { + fun GpuDriverMetadata.toDriver(selected: Boolean = false): Driver = + Driver( + selected, + this.name ?: "", + this.version ?: "", + this.description ?: "" + ) + } +} diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt index 76accf8f3..15ae3a42b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch @@ -17,11 +18,10 @@ import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.features.settings.model.StringSetting import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile -import org.yuzu.yuzu_emu.utils.FileUtil +import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverMetadata import org.yuzu.yuzu_emu.utils.NativeConfig -import java.io.BufferedOutputStream import java.io.File class DriverViewModel : ViewModel() { @@ -38,97 +38,81 @@ class DriverViewModel : ViewModel() { !loading && ready && !deleting }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false) - private val _driverList = MutableStateFlow(GpuDriverHelper.getDrivers()) - val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList + var driverData = GpuDriverHelper.getDrivers() - var previouslySelectedDriver = 0 - var selectedDriver = -1 + private val _driverList = MutableStateFlow(emptyList<Driver>()) + val driverList: StateFlow<List<Driver>> get() = _driverList // Used for showing which driver is currently installed within the driver manager card private val _selectedDriverTitle = MutableStateFlow("") val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle - private val _newDriverInstalled = MutableStateFlow(false) - val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled + private val _showClearButton = MutableStateFlow(false) + val showClearButton = _showClearButton.asStateFlow() - val driversToDelete = mutableListOf<String>() + private val driversToDelete = mutableListOf<String>() init { - val currentDriverMetadata = GpuDriverHelper.installedCustomDriverData - findSelectedDriver(currentDriverMetadata) - - // If a user had installed a driver before the manager was implemented, this zips - // the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can - // be indexed and exported as expected. - if (selectedDriver == -1) { - val driverToSave = - File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip") - driverToSave.createNewFile() - FileUtil.zipFromInternalStorage( - File(GpuDriverHelper.driverInstallationPath!!), - GpuDriverHelper.driverInstallationPath!!, - BufferedOutputStream(driverToSave.outputStream()) - ) - _driverList.value.add(Pair(driverToSave.path, currentDriverMetadata)) - setSelectedDriverIndex(_driverList.value.size - 1) - } + updateDriverList() + updateDriverNameForGame(null) + } - // If a user had installed a driver before the config was reworked to be multiplatform, - // we have save the path of the previously selected driver to the new setting. - if (StringSetting.DRIVER_PATH.getString(true).isEmpty() && selectedDriver > 0 && - StringSetting.DRIVER_PATH.global - ) { - StringSetting.DRIVER_PATH.setString(_driverList.value[selectedDriver].first) - NativeConfig.saveGlobalConfig() - } else { - findSelectedDriver(GpuDriverHelper.customDriverSettingData) + fun reloadDriverData() { + _areDriversLoading.value = true + driverData = GpuDriverHelper.getDrivers() + updateDriverList() + _areDriversLoading.value = false + } + + fun updateDriverList() { + val selectedDriver = GpuDriverHelper.customDriverSettingData + val newDriverList = mutableListOf( + Driver( + selectedDriver == GpuDriverMetadata(), + YuzuApplication.appContext.getString(R.string.system_gpu_driver) + ) + ) + driverData.forEach { + newDriverList.add(it.second.toDriver(it.second == selectedDriver)) } - updateDriverNameForGame(null) + _driverList.value = newDriverList } - fun setSelectedDriverIndex(value: Int) { - if (selectedDriver != -1) { - previouslySelectedDriver = selectedDriver + fun onOpenDriverManager(game: Game?) { + if (game != null) { + SettingsFile.loadCustomConfig(game) } - selectedDriver = value + updateDriverList() } - fun setNewDriverInstalled(value: Boolean) { - _newDriverInstalled.value = value + fun showClearButton(value: Boolean) { + _showClearButton.value = value } - fun addDriver(driverData: Pair<String, GpuDriverMetadata>) { - val driverIndex = _driverList.value.indexOfFirst { it == driverData } - if (driverIndex == -1) { - _driverList.value.add(driverData) - setSelectedDriverIndex(_driverList.value.size - 1) - _selectedDriverTitle.value = driverData.second.name - ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) + fun onDriverSelected(position: Int) { + if (position == 0) { + StringSetting.DRIVER_PATH.setString("") } else { - setSelectedDriverIndex(driverIndex) + StringSetting.DRIVER_PATH.setString(driverData[position - 1].first) } } - fun removeDriver(driverData: Pair<String, GpuDriverMetadata>) { - _driverList.value.remove(driverData) + fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) { + driversToDelete.add(driverData[removedPosition - 1].first) + driverData.removeAt(removedPosition - 1) + onDriverSelected(selectedPosition) } - fun onOpenDriverManager(game: Game?) { - if (game != null) { - SettingsFile.loadCustomConfig(game) - } - - val driverPath = StringSetting.DRIVER_PATH.getString() - if (driverPath.isEmpty()) { - setSelectedDriverIndex(0) - } else { - findSelectedDriver(GpuDriverHelper.getMetadataFromZip(File(driverPath))) + fun onDriverAdded(driver: Pair<String, GpuDriverMetadata>) { + if (driversToDelete.contains(driver.first)) { + driversToDelete.remove(driver.first) } + driverData.add(driver) + onDriverSelected(driverData.size) } fun onCloseDriverManager(game: Game?) { _isDeletingDrivers.value = true - StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first) updateDriverNameForGame(game) if (game == null) { NativeConfig.saveGlobalConfig() @@ -181,20 +165,6 @@ class DriverViewModel : ViewModel() { } } - private fun findSelectedDriver(currentDriverMetadata: GpuDriverMetadata) { - if (driverList.value.size == 1) { - setSelectedDriverIndex(0) - return - } - - driverList.value.forEachIndexed { i: Int, driver: Pair<String, GpuDriverMetadata> -> - if (driver.second == currentDriverMetadata) { - setSelectedDriverIndex(i) - return - } - } - } - fun updateDriverNameForGame(game: Game?) { if (!GpuDriverHelper.supportsCustomDriverLoading()) { return @@ -217,7 +187,6 @@ class DriverViewModel : ViewModel() { private fun setDriverReady() { _isDriverReady.value = true - _selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name - ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver) + updateName() } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt new file mode 100644 index 000000000..11c22d323 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.model + +interface SelectableItem { + var selected: Boolean + fun onSelectionStateChanged(selected: Boolean) +} 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 622ae996e..644289e25 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 @@ -41,6 +41,7 @@ import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.model.AddonViewModel +import org.yuzu.yuzu_emu.model.DriverViewModel import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.TaskState @@ -58,6 +59,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { private val gamesViewModel: GamesViewModel by viewModels() private val taskViewModel: TaskViewModel by viewModels() private val addonViewModel: AddonViewModel by viewModels() + private val driverViewModel: DriverViewModel by viewModels() override var themeId: Int = 0 @@ -689,6 +691,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { NativeLibrary.initializeSystem(true) NativeConfig.initializeGlobalConfig() gamesViewModel.reloadGames(false) + driverViewModel.reloadDriverData() return@newInstance getString(R.string.user_data_import_success) }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) 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 685272288..a8f9dcc34 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 @@ -62,9 +62,6 @@ object GpuDriverHelper { ?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name } ?.distinct() ?.toMutableList() ?: mutableListOf() - - // TODO: Get system driver information - drivers.add(0, Pair("", GpuDriverMetadata())) return drivers } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt new file mode 100644 index 000000000..7101ad434 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.viewholder + +import androidx.recyclerview.widget.RecyclerView +import androidx.viewbinding.ViewBinding +import org.yuzu.yuzu_emu.adapters.AbstractDiffAdapter +import org.yuzu.yuzu_emu.adapters.AbstractListAdapter + +/** + * [RecyclerView.ViewHolder] meant to work together with a [AbstractDiffAdapter] or a + * [AbstractListAdapter] so we can run [bind] on each list item without needing a manual hookup. + */ +abstract class AbstractViewHolder<Model>(binding: ViewBinding) : + RecyclerView.ViewHolder(binding.root) { + abstract fun bind(model: Model) +} diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 136c8dee6..e436622e0 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -410,8 +410,8 @@ void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) { jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { - handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); - controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); + handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); handheld->Disconnect(); } } diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml index a26ffbc73..655e49219 100644 --- a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml +++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml @@ -147,7 +147,7 @@ android:layout_marginHorizontal="20dp" /> <LinearLayout - android:id="@+id/button_build_hash" + android:id="@+id/button_version_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/selectableItemBackground" @@ -164,7 +164,7 @@ android:textAlignment="viewStart" /> <com.google.android.material.textview.MaterialTextView - android:id="@+id/text_build_hash" + android:id="@+id/text_version_name" style="@style/TextAppearance.Material3.BodyMedium" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml index a24f5230e..38090fa50 100644 --- a/src/android/app/src/main/res/layout/fragment_about.xml +++ b/src/android/app/src/main/res/layout/fragment_about.xml @@ -148,7 +148,7 @@ android:layout_marginHorizontal="20dp" /> <LinearLayout - android:id="@+id/button_build_hash" + android:id="@+id/button_version_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingVertical="16dp" @@ -165,7 +165,7 @@ android:text="@string/build" /> <com.google.android.material.textview.MaterialTextView - android:id="@+id/text_build_hash" + android:id="@+id/text_version_name" style="@style/TextAppearance.Material3.BodyMedium" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/src/android/app/src/main/res/menu/menu_driver_manager.xml b/src/android/app/src/main/res/menu/menu_driver_manager.xml new file mode 100644 index 000000000..dee5d57b6 --- /dev/null +++ b/src/android/app/src/main/res/menu/menu_driver_manager.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/menu_driver_clear" + android:icon="@drawable/ic_clear" + android:title="@string/clear" + app:showAsAction="always" /> + +</menu> diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 0deea9c58..a249dc5f7 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -64,7 +64,7 @@ public: return [this] { ShutdownThreadFunction(); }; } - void PreemptSingleCore(bool from_running_enviroment = true); + void PreemptSingleCore(bool from_running_environment = true); std::size_t CurrentCore() const { return current_core.load(); diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 66e46c4ba..4051ed4af 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -559,28 +559,28 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>& } constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{ - {"----- Free -----", Kernel::Svc::MemoryState::Free}, - {"Io ", Kernel::Svc::MemoryState::Io}, - {"Static ", Kernel::Svc::MemoryState::Static}, - {"Code ", Kernel::Svc::MemoryState::Code}, - {"CodeData ", Kernel::Svc::MemoryState::CodeData}, - {"Normal ", Kernel::Svc::MemoryState::Normal}, - {"Shared ", Kernel::Svc::MemoryState::Shared}, - {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, - {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, - {"Ipc ", Kernel::Svc::MemoryState::Ipc}, - {"Stack ", Kernel::Svc::MemoryState::Stack}, - {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, - {"Transfered ", Kernel::Svc::MemoryState::Transfered}, - {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered}, - {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, - {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, - {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, - {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, - {"Kernel ", Kernel::Svc::MemoryState::Kernel}, - {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, - {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, - {"Coverage ", Kernel::Svc::MemoryState::Coverage}, + {"----- Free ------", Kernel::Svc::MemoryState::Free}, + {"Io ", Kernel::Svc::MemoryState::Io}, + {"Static ", Kernel::Svc::MemoryState::Static}, + {"Code ", Kernel::Svc::MemoryState::Code}, + {"CodeData ", Kernel::Svc::MemoryState::CodeData}, + {"Normal ", Kernel::Svc::MemoryState::Normal}, + {"Shared ", Kernel::Svc::MemoryState::Shared}, + {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, + {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, + {"Ipc ", Kernel::Svc::MemoryState::Ipc}, + {"Stack ", Kernel::Svc::MemoryState::Stack}, + {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, + {"Transferred ", Kernel::Svc::MemoryState::Transferred}, + {"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred}, + {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, + {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, + {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, + {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, + {"Kernel ", Kernel::Svc::MemoryState::Kernel}, + {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, + {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, + {"Coverage ", Kernel::Svc::MemoryState::Coverage}, }}; static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 34fe23b6a..e04d884ba 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -47,7 +47,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac // Connect controllers based on the following priority list from highest to lowest priority: // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld if (parameters.allow_pro_controller) { - controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); + controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); controller->Connect(true); } else if (parameters.allow_dual_joycons) { controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index ef3f61321..d2b7e9a66 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h @@ -81,12 +81,12 @@ enum class KMemoryState : u32 { ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped, - Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | - FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | - FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc | + FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | + FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | - FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc | + FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc | @@ -130,8 +130,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09); static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A); static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B); static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C); -static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D); -static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E); +static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x055C3C0D); +static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x045C380E); static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F); static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811); diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index 8c1549559..73fbda331 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp @@ -486,8 +486,8 @@ KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const { case Svc::MemoryState::Shared: case Svc::MemoryState::AliasCode: case Svc::MemoryState::AliasCodeData: - case Svc::MemoryState::Transfered: - case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::Transferred: + case Svc::MemoryState::SharedTransferred: case Svc::MemoryState::SharedCode: case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::CodeOut: @@ -522,8 +522,8 @@ size_t KPageTableBase::GetRegionSize(Svc::MemoryState state) const { case Svc::MemoryState::Shared: case Svc::MemoryState::AliasCode: case Svc::MemoryState::AliasCodeData: - case Svc::MemoryState::Transfered: - case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::Transferred: + case Svc::MemoryState::SharedTransferred: case Svc::MemoryState::SharedCode: case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::CodeOut: @@ -564,8 +564,8 @@ bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, Svc::MemorySt case Svc::MemoryState::AliasCodeData: case Svc::MemoryState::Stack: case Svc::MemoryState::ThreadLocal: - case Svc::MemoryState::Transfered: - case Svc::MemoryState::SharedTransfered: + case Svc::MemoryState::Transferred: + case Svc::MemoryState::SharedTransferred: case Svc::MemoryState::SharedCode: case Svc::MemoryState::GeneratedCode: case Svc::MemoryState::CodeOut: diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp index 0e2e11743..cbb1b02bb 100644 --- a/src/core/hle/kernel/k_transfer_memory.cpp +++ b/src/core/hle/kernel/k_transfer_memory.cpp @@ -76,8 +76,8 @@ Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPer // Map the memory. const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) - ? KMemoryState::Transfered - : KMemoryState::SharedTransfered; + ? KMemoryState::Transferred + : KMemoryState::SharedTransferred; R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup( address, *m_page_group, state, KMemoryPermission::UserReadWrite)); @@ -96,8 +96,8 @@ Result KTransferMemory::Unmap(KProcessAddress address, size_t size) { // Unmap the memory. const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) - ? KMemoryState::Transfered - : KMemoryState::SharedTransfered; + ? KMemoryState::Transferred + : KMemoryState::SharedTransferred; R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state)); // Mark ourselves as unmapped. diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp index 1f97121b3..671bca23f 100644 --- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp +++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp @@ -90,7 +90,7 @@ Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t add // Verify that the mapping is in range. R_UNLESS(GetCurrentProcess(system.Kernel()) .GetPageTable() - .CanContain(address, size, KMemoryState::Transfered), + .CanContain(address, size, KMemoryState::Transferred), ResultInvalidMemoryRegion); // Map the transfer memory. @@ -117,7 +117,7 @@ Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t a // Verify that the mapping is in range. R_UNLESS(GetCurrentProcess(system.Kernel()) .GetPageTable() - .CanContain(address, size, KMemoryState::Transfered), + .CanContain(address, size, KMemoryState::Transferred), ResultInvalidMemoryRegion); // Unmap the transfer memory. diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 50de02e36..ab432ea78 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h @@ -27,8 +27,8 @@ enum class MemoryState : u32 { Ipc = 0x0A, Stack = 0x0B, ThreadLocal = 0x0C, - Transfered = 0x0D, - SharedTransfered = 0x0E, + Transferred = 0x0D, + SharedTransferred = 0x0E, SharedCode = 0x0F, Inaccessible = 0x10, NonSecureIpc = 0x11, diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h index 369f9250f..673eed516 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.h +++ b/src/core/hle/service/am/applets/applet_profile_select.h @@ -76,7 +76,7 @@ struct UiSettingsDisplayOptions { bool is_system_or_launcher; bool is_registration_permitted; bool show_skip_button; - bool aditional_select; + bool additional_select; bool show_user_selector; bool is_unqualified_user_selectable; }; diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 96b225d5f..261fc204c 100644 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp @@ -85,7 +85,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu } Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, - ContentType contex_type, s64 start_posix_time, + ContentType content_type, s64 start_posix_time, s64 end_posix_time, u64 aruid) const { if (!is_mounted) { return ResultIsNotMounted; @@ -94,7 +94,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou std::vector<ApplicationAlbumEntry> album_entries; const auto start_date = ConvertToAlbumDateTime(start_posix_time); const auto end_date = ConvertToAlbumDateTime(end_posix_time); - const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid); + const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid); if (result.IsError()) { return result; @@ -113,14 +113,14 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou } Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, - ContentType contex_type, AlbumFileDateTime start_date, + ContentType content_type, AlbumFileDateTime start_date, AlbumFileDateTime end_date, u64 aruid) const { if (!is_mounted) { return ResultIsNotMounted; } for (auto& [file_id, path] : album_files) { - if (file_id.type != contex_type) { + if (file_id.type != content_type) { continue; } if (file_id.date > start_date) { @@ -139,7 +139,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en .hash{}, .datetime = file_id.date, .storage = file_id.storage, - .content = contex_type, + .content = content_type, .unknown = 1, }; out_entries.push_back(entry); diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h index e20c70c7b..6fd34f589 100644 --- a/src/core/hle/service/caps/caps_manager.h +++ b/src/core/hle/service/caps/caps_manager.h @@ -45,10 +45,10 @@ public: Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, u8 flags) const; Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, - ContentType contex_type, s64 start_posix_time, s64 end_posix_time, + ContentType content_type, s64 start_posix_time, s64 end_posix_time, u64 aruid) const; Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, - ContentType contex_type, AlbumFileDateTime start_date, + ContentType content_type, AlbumFileDateTime start_date, AlbumFileDateTime end_date, u64 aruid) const; Result GetAutoSavingStorage(bool& out_is_autosaving) const; Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, diff --git a/src/core/hle/service/caps/caps_result.h b/src/core/hle/service/caps/caps_result.h index c65e5fb9a..179ae4840 100644 --- a/src/core/hle/service/caps/caps_result.h +++ b/src/core/hle/service/caps/caps_result.h @@ -12,7 +12,7 @@ constexpr Result ResultUnknown5(ErrorModule::Capture, 5); constexpr Result ResultUnknown6(ErrorModule::Capture, 6); constexpr Result ResultUnknown7(ErrorModule::Capture, 7); constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); -constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); +constexpr Result ResultInvalidTimestamp(ErrorModule::Capture, 12); constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 0507b14e7..aeb849efa 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -131,7 +131,7 @@ private: u8 is_favorite; u8 same_app; u8 same_app_played; - u8 arbitary_app_played; + u8 arbitrary_app_played; u64 group_id; }; static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index fc8a3ab66..fc03a0a5f 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -18,23 +18,23 @@ namespace Service::HID { void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); - std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system); + std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system); std::shared_ptr<HidFirmwareSettings> firmware_settings = std::make_shared<HidFirmwareSettings>(); // TODO: Remove this hack until this service is emulated properly. const auto process_list = system.Kernel().GetProcessList(); if (!process_list.empty()) { - resouce_manager->Initialize(); - resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); + resource_manager->Initialize(); + resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); } server_manager->RegisterNamedService( - "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); + "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); server_manager->RegisterNamedService( - "hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager)); + "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager)); server_manager->RegisterNamedService( - "hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager)); + "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager)); server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index 74898888a..1951da33b 100644 --- a/src/core/hle/service/hid/hid_server.cpp +++ b/src/core/hle/service/hid/hid_server.cpp @@ -1498,7 +1498,7 @@ void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) { bool check_device_index = false; switch (vibration_device_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::JoyconLeft: diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index 46f503d38..c903ee8b8 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp @@ -67,7 +67,7 @@ HidBus::~HidBus() { void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { if (is_hidbus_enabled) { for (std::size_t i = 0; i < devices.size(); ++i) { - if (!devices[i].is_device_initializated) { + if (!devices[i].is_device_initialized) { continue; } auto& device = devices[i].device; @@ -213,7 +213,7 @@ void HidBus::Initialize(HLERequestContext& ctx) { if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { MakeDevice<RingController>(bus_handle_); - devices[device_index.value()].is_device_initializated = true; + devices[device_index.value()].is_device_initialized = true; devices[device_index.value()].device->ActivateDevice(); cur_entry.is_in_focus = true; cur_entry.is_connected = true; @@ -222,7 +222,7 @@ void HidBus::Initialize(HLERequestContext& ctx) { cur_entry.is_polling_mode = false; } else { MakeDevice<HidbusStubbed>(bus_handle_); - devices[device_index.value()].is_device_initializated = true; + devices[device_index.value()].is_device_initialized = true; cur_entry.is_in_focus = true; cur_entry.is_connected = false; cur_entry.is_connected_result = ResultSuccess; @@ -261,7 +261,7 @@ void HidBus::Finalize(HLERequestContext& ctx) { const auto entry_index = devices[device_index.value()].handle.internal_index; auto& cur_entry = hidbus_status.entries[entry_index]; auto& device = devices[device_index.value()].device; - devices[device_index.value()].is_device_initializated = false; + devices[device_index.value()].is_device_initialized = false; device->DeactivateDevice(); cur_entry.is_in_focus = true; diff --git a/src/core/hle/service/hid/hidbus.h b/src/core/hle/service/hid/hidbus.h index 05f62f634..03d9f6863 100644 --- a/src/core/hle/service/hid/hidbus.h +++ b/src/core/hle/service/hid/hidbus.h @@ -89,7 +89,7 @@ private: static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size"); struct HidbusDevice { - bool is_device_initializated{}; + bool is_device_initialized{}; BusHandle handle{}; std::unique_ptr<HidbusBase> device{nullptr}; }; diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 39df77e43..3f38ceb03 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp @@ -181,22 +181,22 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { } } - buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); - buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); - buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); - buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); + buffer_x_descriptors.reserve(command_header->num_buf_x_descriptors); + buffer_a_descriptors.reserve(command_header->num_buf_a_descriptors); + buffer_b_descriptors.reserve(command_header->num_buf_b_descriptors); + buffer_w_descriptors.reserve(command_header->num_buf_w_descriptors); for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { - buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); + buffer_x_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); } for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { - buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); + buffer_a_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { - buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); + buffer_b_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { - buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); + buffer_w_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; @@ -246,7 +246,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { if (command_header->buf_c_descriptor_flags == IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { - buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); + buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); } else { u32 num_buf_c_descriptors = static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; @@ -256,7 +256,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { ASSERT(num_buf_c_descriptors < 14); for (u32 i = 0; i < num_buf_c_descriptors; ++i) { - buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); + buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); } } } diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h index 40d86943e..440737db5 100644 --- a/src/core/hle/service/hle_ipc.h +++ b/src/core/hle/service/hle_ipc.h @@ -232,19 +232,19 @@ public: } [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { - return buffer_x_desciptors; + return buffer_x_descriptors; } [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { - return buffer_a_desciptors; + return buffer_a_descriptors; } [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { - return buffer_b_desciptors; + return buffer_b_descriptors; } [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { - return buffer_c_desciptors; + return buffer_c_descriptors; } [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { @@ -406,11 +406,11 @@ private: std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; std::optional<IPC::DataPayloadHeader> data_payload_header; std::optional<IPC::DomainMessageHeader> domain_message_header; - std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; - std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; - std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; - std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; - std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; + std::vector<IPC::BufferDescriptorX> buffer_x_descriptors; + std::vector<IPC::BufferDescriptorABW> buffer_a_descriptors; + std::vector<IPC::BufferDescriptorABW> buffer_b_descriptors; + std::vector<IPC::BufferDescriptorABW> buffer_w_descriptors; + std::vector<IPC::BufferDescriptorC> buffer_c_descriptors; u32_le command{}; u64 pid{}; diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp index 9556e9193..4274a92c9 100644 --- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp +++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp @@ -19,7 +19,7 @@ namespace Service::NFP::AmiiboCrypto { bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { const auto& amiibo_data = ntag_file.user_memory; LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock); - LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", ntag_file.compability_container); + LOG_DEBUG(Service_NFP, "compatibility_container=0x{0:x}", ntag_file.compatibility_container); LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter)); LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); @@ -49,7 +49,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { if (ntag_file.static_lock != 0xE00F) { return false; } - if (ntag_file.compability_container != 0xEEFF10F1U) { + if (ntag_file.compatibility_container != 0xEEFF10F1U) { return false; } if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) { @@ -78,7 +78,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) { encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2; encoded_data.internal_number = nfc_data.internal_number; encoded_data.static_lock = nfc_data.static_lock; - encoded_data.compability_container = nfc_data.compability_container; + encoded_data.compatibility_container = nfc_data.compatibility_container; encoded_data.hmac_data = nfc_data.user_memory.hmac_data; encoded_data.constant_value = nfc_data.user_memory.constant_value; encoded_data.write_counter = nfc_data.user_memory.write_counter; @@ -112,7 +112,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) { nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2; nfc_data.internal_number = encoded_data.internal_number; nfc_data.static_lock = encoded_data.static_lock; - nfc_data.compability_container = encoded_data.compability_container; + nfc_data.compatibility_container = encoded_data.compatibility_container; nfc_data.user_memory.hmac_data = encoded_data.hmac_data; nfc_data.user_memory.constant_value = encoded_data.constant_value; nfc_data.user_memory.write_counter = encoded_data.write_counter; @@ -257,7 +257,7 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou out_data.uid_crc_check2 = in_data.uid_crc_check2; out_data.internal_number = in_data.internal_number; out_data.static_lock = in_data.static_lock; - out_data.compability_container = in_data.compability_container; + out_data.compatibility_container = in_data.compatibility_container; out_data.constant_value = in_data.constant_value; out_data.write_counter = in_data.write_counter; diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index b37fb6da3..31cc87acc 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp @@ -75,7 +75,7 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { return; } - if (!is_initalized) { + if (!is_initialized) { return; } @@ -207,7 +207,7 @@ void NfcDevice::Initialize() { return; } - is_initalized = npad_device->AddNfcHandle(); + is_initialized = npad_device->AddNfcHandle(); } void NfcDevice::Finalize() { @@ -226,7 +226,7 @@ void NfcDevice::Finalize() { } device_state = DeviceState::Unavailable; - is_initalized = false; + is_initialized = false; } Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h index d8efe25ec..15f9b25da 100644 --- a/src/core/hle/service/nfc/common/device.h +++ b/src/core/hle/service/nfc/common/device.h @@ -126,7 +126,7 @@ private: Kernel::KEvent* deactivate_event = nullptr; Kernel::KEvent* availability_change_event = nullptr; - bool is_initalized{}; + bool is_initialized{}; NfcProtocol allowed_protocols{}; DeviceState device_state{DeviceState::Unavailable}; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index f96d21220..2505eb551 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -243,12 +243,12 @@ static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid si struct NTAG215File { u8 uid_crc_check2; u8 internal_number; - u16 static_lock; // Set defined pages as read only - u32 compability_container; // Defines available memory - HashData hmac_data; // Hash - u8 constant_value; // Must be A5 - u16_be write_counter; // Number of times the amiibo has been written? - u8 amiibo_version; // Amiibo file version + u16 static_lock; // Set defined pages as read only + u32 compatibility_container; // Defines available memory + HashData hmac_data; // Hash + u8 constant_value; // Must be A5 + u16_be write_counter; // Number of times the amiibo has been written? + u8 amiibo_version; // Amiibo file version AmiiboSettings settings; Service::Mii::Ver3StoreData owner_mii; // Mii data u64_be application_id; // Game id @@ -278,7 +278,7 @@ struct EncryptedNTAG215File { u8 uuid_crc_check2; u8 internal_number; u16 static_lock; // Set defined pages as read only - u32 compability_container; // Defines available memory + u32 compatibility_container; // Defines available memory EncryptedAmiiboFile user_memory; // Writable data u32 dynamic_lock; // Dynamic lock u32 CFG0; // Defines memory protected by password diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 932997e75..79a21683d 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -90,7 +90,7 @@ private: u64_le align; }; }; - static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); + static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitializeEx is incorrect size"); struct IoctlFreeSpace { u64_le offset{}; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 61a2df121..3e0c96456 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices { nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) : nvdevice{system_}, events_interface{events_interface_} { error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); - unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); + unknown_event = events_interface.CreateEvent("CtrlGpuUnknownEvent"); } nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { events_interface.FreeEvent(error_notifier_event); diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h index 0e2f47075..38f35e79f 100644 --- a/src/core/hle/service/nvdrv/nvdata.h +++ b/src/core/hle/service/nvdrv/nvdata.h @@ -51,7 +51,7 @@ enum class NvResult : u32 { DispNoDisplaysAttached = 0x20003, DispModeNotSupported = 0x20004, DispNotFound = 0x20005, - DispAttachDissallowed = 0x20006, + DispAttachDisallowed = 0x20006, DispTypeNotSupported = 0x20007, DispAuthenticationFailed = 0x20008, DispNotAttached = 0x20009, diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index aa8aaa2d9..0469110e8 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -223,7 +223,8 @@ Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64 return VI::ResultNotFound; } - return display->GetVSyncEvent(out_vsync_event); + *out_vsync_event = display->GetVSyncEvent(); + return ResultSuccess; } VI::Display* Nvnflinger::FindDisplay(u64 display_id) { diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp index c13ffa6f6..3d0f2aeb7 100644 --- a/src/core/hle/service/pcv/pcv.cpp +++ b/src/core/hle/service/pcv/pcv.cpp @@ -54,8 +54,8 @@ public: class IClkrstSession final : public ServiceFramework<IClkrstSession> { public: - explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_) - : ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) { + explicit IClkrstSession(Core::System& system_, DeviceCode device_code_) + : ServiceFramework{system_, "IClkrstSession"}, device_code(device_code_) { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "SetClockEnabled"}, @@ -93,7 +93,7 @@ private: rb.Push<u32>(clock_rate); } - DeviceCode deivce_code; + DeviceCode device_code; u32 clock_rate{}; }; @@ -118,9 +118,9 @@ private: void OpenSession(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>()); - const auto unkonwn_input = rp.Pop<u32>(); + const auto unknown_input = rp.Pop<u32>(); - LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input); + LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unknown_input); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/set/system_settings.cpp b/src/core/hle/service/set/system_settings.cpp index 2723417ad..5977429b2 100644 --- a/src/core/hle/service/set/system_settings.cpp +++ b/src/core/hle/service/set/system_settings.cpp @@ -28,7 +28,7 @@ SystemSettings DefaultSystemSettings() { .cmu_mode = CmuMode::None, .tv_underscan = {}, .tv_gama = 1.0f, - .constrast_ratio = 0.5f, + .contrast_ratio = 0.5f, }; settings.initial_launch_settings_packed = { diff --git a/src/core/hle/service/set/system_settings.h b/src/core/hle/service/set/system_settings.h index ded2906ad..6ec9e71e7 100644 --- a/src/core/hle/service/set/system_settings.h +++ b/src/core/hle/service/set/system_settings.h @@ -208,7 +208,7 @@ struct TvSettings { CmuMode cmu_mode; u32 tv_underscan; f32 tv_gama; - f32 constrast_ratio; + f32 contrast_ratio; }; static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); @@ -341,7 +341,7 @@ struct SystemSettings { std::array<u8, 0x3C> reserved_09934; // nn::settings::system::ErrorReportSharePermission - ErrorReportSharePermission error_report_share_permssion; + ErrorReportSharePermission error_report_share_permission; std::array<u8, 0x3C> reserved_09974; diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp index f7ad6193e..af9348522 100644 --- a/src/core/hle/service/set/system_settings_server.cpp +++ b/src/core/hle/service/set/system_settings_server.cpp @@ -721,10 +721,10 @@ void ISystemSettingsServer::SetTvSettings(HLERequestContext& ctx) { SetSaveNeeded(); LOG_INFO(Service_SET, - "called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, " + "called, flags={}, cmu_mode={}, contrast_ratio={}, hdmi_content_type={}, " "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, - m_system_settings.tv_settings.constrast_ratio, + m_system_settings.tv_settings.contrast_ratio, m_system_settings.tv_settings.hdmi_content_type, m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, m_system_settings.tv_settings.tv_resolution, @@ -870,10 +870,10 @@ void ISystemSettingsServer::GetInitialLaunchSettings(HLERequestContext& ctx) { void ISystemSettingsServer::SetInitialLaunchSettings(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - auto inital_launch_settings = rp.PopRaw<InitialLaunchSettings>(); + auto initial_launch_settings = rp.PopRaw<InitialLaunchSettings>(); - m_system_settings.initial_launch_settings_packed.flags = inital_launch_settings.flags; - m_system_settings.initial_launch_settings_packed.timestamp = inital_launch_settings.timestamp; + m_system_settings.initial_launch_settings_packed.flags = initial_launch_settings.flags; + m_system_settings.initial_launch_settings_packed.timestamp = initial_launch_settings.timestamp; SetSaveNeeded(); LOG_INFO(Service_SET, "called, flags={}, timestamp={}", diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index 71ce9be50..e2d9cd98a 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -71,18 +71,7 @@ size_t Display::GetNumLayers() const { return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); } -Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) { - if (got_vsync_event) { - return ResultPermissionDenied; - } - - got_vsync_event = true; - - *out_vsync_event = GetVSyncEventUnchecked(); - return ResultSuccess; -} - -Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() { +Kernel::KReadableEvent* Display::GetVSyncEvent() { return &vsync_event->GetReadableEvent(); } diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 1d9360b96..7e68ee79b 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -74,16 +74,8 @@ public: std::size_t GetNumLayers() const; - /** - * Gets the internal vsync event. - * - * @returns The internal Vsync event if it has not yet been retrieved, - * VI::ResultPermissionDenied otherwise. - */ - [[nodiscard]] Result GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event); - /// Gets the internal vsync event. - Kernel::KReadableEvent* GetVSyncEventUnchecked(); + Kernel::KReadableEvent* GetVSyncEvent(); /// Signals the internal vsync event. void SignalVSyncEvent(); @@ -104,7 +96,6 @@ public: /// Resets the display for a new connection. void Reset() { layers.clear(); - got_vsync_event = false; } /// Attempts to find a layer with the given ID. @@ -133,7 +124,6 @@ private: std::vector<std::unique_ptr<Layer>> layers; Kernel::KEvent* vsync_event{}; - bool got_vsync_event{false}; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 9ab8788e3..39d5be90d 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -343,8 +343,8 @@ private: class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { public: - explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_) - : ServiceFramework{system_, "IManagerDisplayService"}, nv_flinger{nv_flinger_} { + explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_) + : ServiceFramework{system_, "IManagerDisplayService"}, nvnflinger{nvnflinger_} { // clang-format off static const FunctionInfo functions[] = { {200, nullptr, "AllocateProcessHeapBlock"}, @@ -440,7 +440,7 @@ private: IPC::RequestParser rp{ctx}; const u64 display = rp.Pop<u64>(); - const Result rc = nv_flinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; + const Result rc = nvnflinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(rc); @@ -457,7 +457,7 @@ private: "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", unknown, display, aruid); - const auto layer_id = nv_flinger.CreateLayer(display); + const auto layer_id = nvnflinger.CreateLayer(display); if (!layer_id) { LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); IPC::ResponseBuilder rb{ctx, 2}; @@ -494,14 +494,14 @@ private: rb.Push(ResultSuccess); } - Nvnflinger::Nvnflinger& nv_flinger; + Nvnflinger::Nvnflinger& nvnflinger; }; class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { public: - IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_, + IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_) - : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_}, + : ServiceFramework{system_, "IApplicationDisplayService"}, nvnflinger{nvnflinger_}, hos_binder_driver_server{hos_binder_driver_server_} { static const FunctionInfo functions[] = { @@ -564,7 +564,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger); + rb.PushIpcInterface<ISystemDisplayService>(system, nvnflinger); } void GetManagerDisplayService(HLERequestContext& ctx) { @@ -572,7 +572,7 @@ private: IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IManagerDisplayService>(system, nv_flinger); + rb.PushIpcInterface<IManagerDisplayService>(system, nvnflinger); } void GetIndirectDisplayTransactionService(HLERequestContext& ctx) { @@ -607,7 +607,7 @@ private: ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); - const auto display_id = nv_flinger.OpenDisplay(name); + const auto display_id = nvnflinger.OpenDisplay(name); if (!display_id) { LOG_ERROR(Service_VI, "Display not found! display_name={}", name); IPC::ResponseBuilder rb{ctx, 2}; @@ -624,7 +624,7 @@ private: IPC::RequestParser rp{ctx}; const u64 display_id = rp.Pop<u64>(); - const Result rc = nv_flinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; + const Result rc = nvnflinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; IPC::ResponseBuilder rb{ctx, 2}; rb.Push(rc); @@ -703,7 +703,7 @@ private: LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); - const auto display_id = nv_flinger.OpenDisplay(display_name); + const auto display_id = nvnflinger.OpenDisplay(display_name); if (!display_id) { LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -711,7 +711,7 @@ private: return; } - const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id); + const auto buffer_queue_id = nvnflinger.FindBufferQueueId(*display_id, layer_id); if (!buffer_queue_id) { LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -719,7 +719,7 @@ private: return; } - nv_flinger.OpenLayer(layer_id); + nvnflinger.OpenLayer(layer_id); android::OutputParcel parcel; parcel.WriteInterface(NativeWindow{*buffer_queue_id}); @@ -737,7 +737,7 @@ private: LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); - nv_flinger.CloseLayer(layer_id); + nvnflinger.CloseLayer(layer_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -753,7 +753,7 @@ private: // TODO(Subv): What's the difference between a Stray and a Managed layer? - const auto layer_id = nv_flinger.CreateLayer(display_id); + const auto layer_id = nvnflinger.CreateLayer(display_id); if (!layer_id) { LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -761,7 +761,7 @@ private: return; } - const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id); + const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); if (!buffer_queue_id) { LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -785,7 +785,7 @@ private: const u64 layer_id = rp.Pop<u64>(); LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); - nv_flinger.DestroyLayer(layer_id); + nvnflinger.DestroyLayer(layer_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -798,7 +798,7 @@ private: LOG_DEBUG(Service_VI, "called. display_id={}", display_id); Kernel::KReadableEvent* vsync_event{}; - const auto result = nv_flinger.FindVsyncEvent(&vsync_event, display_id); + const auto result = nvnflinger.FindVsyncEvent(&vsync_event, display_id); if (result != ResultSuccess) { if (result == ResultNotFound) { LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); @@ -808,6 +808,12 @@ private: rb.Push(result); return; } + if (vsync_event_fetched) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(VI::ResultPermissionDenied); + return; + } + vsync_event_fetched = true; IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); @@ -899,8 +905,9 @@ private: } } - Nvnflinger::Nvnflinger& nv_flinger; + Nvnflinger::Nvnflinger& nvnflinger; Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; + bool vsync_event_fetched{false}; }; static bool IsValidServiceAccess(Permission permission, Policy policy) { @@ -916,7 +923,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) { } void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, - Nvnflinger::Nvnflinger& nv_flinger, + Nvnflinger::Nvnflinger& nvnflinger, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, Permission permission) { IPC::RequestParser rp{ctx}; @@ -931,19 +938,19 @@ void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server); + rb.PushIpcInterface<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server); } -void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger, +void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) { auto server_manager = std::make_unique<ServerManager>(system); server_manager->RegisterNamedService( - "vi:m", std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)); + "vi:m", std::make_shared<VI_M>(system, nvnflinger, hos_binder_driver_server)); server_manager->RegisterNamedService( - "vi:s", std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)); + "vi:s", std::make_shared<VI_S>(system, nvnflinger, hos_binder_driver_server)); server_manager->RegisterNamedService( - "vi:u", std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)); + "vi:u", std::make_shared<VI_U>(system, nvnflinger, hos_binder_driver_server)); ServerManager::RunServer(std::move(server_manager)); } diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h index a35b62f97..ee4bcbcfa 100644 --- a/src/core/hle/service/vi/vi.h +++ b/src/core/hle/service/vi/vi.h @@ -48,7 +48,7 @@ void GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, Permission permission); } // namespace detail -void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger, +void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger, Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); } // namespace Service::VI diff --git a/src/hid_core/CMakeLists.txt b/src/hid_core/CMakeLists.txt index cce4e6857..aa85502b5 100644 --- a/src/hid_core/CMakeLists.txt +++ b/src/hid_core/CMakeLists.txt @@ -36,6 +36,30 @@ add_library(hid_core STATIC irsensor/processor_base.h irsensor/tera_plugin_processor.cpp irsensor/tera_plugin_processor.h + resources/abstracted_pad/abstract_battery_handler.cpp + resources/abstracted_pad/abstract_battery_handler.h + resources/abstracted_pad/abstract_button_handler.cpp + resources/abstracted_pad/abstract_button_handler.h + resources/abstracted_pad/abstract_ir_sensor_handler.cpp + resources/abstracted_pad/abstract_ir_sensor_handler.h + resources/abstracted_pad/abstract_led_handler.cpp + resources/abstracted_pad/abstract_led_handler.h + resources/abstracted_pad/abstract_mcu_handler.cpp + resources/abstracted_pad/abstract_mcu_handler.h + resources/abstracted_pad/abstract_nfc_handler.cpp + resources/abstracted_pad/abstract_nfc_handler.h + resources/abstracted_pad/abstract_pad.cpp + resources/abstracted_pad/abstract_pad.h + resources/abstracted_pad/abstract_pad_holder.cpp + resources/abstracted_pad/abstract_pad_holder.h + resources/abstracted_pad/abstract_palma_handler.cpp + resources/abstracted_pad/abstract_palma_handler.h + resources/abstracted_pad/abstract_properties_handler.cpp + resources/abstracted_pad/abstract_properties_handler.h + resources/abstracted_pad/abstract_sixaxis_handler.cpp + resources/abstracted_pad/abstract_sixaxis_handler.h + resources/abstracted_pad/abstract_vibration_handler.cpp + resources/abstracted_pad/abstract_vibration_handler.h resources/debug_pad/debug_pad.cpp resources/debug_pad/debug_pad.h resources/debug_pad/debug_pad_types.h @@ -56,6 +80,8 @@ add_library(hid_core STATIC resources/npad/npad_resource.cpp resources/npad/npad_resource.h resources/npad/npad_types.h + resources/npad/npad_vibration.cpp + resources/npad/npad_vibration.h resources/palma/palma.cpp resources/palma/palma.h resources/six_axis/console_six_axis.cpp @@ -78,6 +104,14 @@ add_library(hid_core STATIC resources/touch_screen/touch_types.h resources/unique_pad/unique_pad.cpp resources/unique_pad/unique_pad.h + resources/vibration/gc_vibration_device.h + resources/vibration/gc_vibration_device.cpp + resources/vibration/n64_vibration_device.h + resources/vibration/n64_vibration_device.cpp + resources/vibration/vibration_base.h + resources/vibration/vibration_base.cpp + resources/vibration/vibration_device.h + resources/vibration/vibration_device.cpp resources/applet_resource.cpp resources/applet_resource.h resources/controller_base.cpp diff --git a/src/hid_core/frontend/emulated_controller.cpp b/src/hid_core/frontend/emulated_controller.cpp index 3d2d1e9f9..a6a96935d 100644 --- a/src/hid_core/frontend/emulated_controller.cpp +++ b/src/hid_core/frontend/emulated_controller.cpp @@ -27,7 +27,7 @@ EmulatedController::~EmulatedController() = default; NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) { switch (type) { case Settings::ControllerType::ProController: - return NpadStyleIndex::ProController; + return NpadStyleIndex::Fullkey; case Settings::ControllerType::DualJoyconDetached: return NpadStyleIndex::JoyconDual; case Settings::ControllerType::LeftJoycon: @@ -49,13 +49,13 @@ NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerTyp case Settings::ControllerType::SegaGenesis: return NpadStyleIndex::SegaGenesis; default: - return NpadStyleIndex::ProController; + return NpadStyleIndex::Fullkey; } } Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) { switch (type) { - case NpadStyleIndex::ProController: + case NpadStyleIndex::Fullkey: return Settings::ControllerType::ProController; case NpadStyleIndex::JoyconDual: return Settings::ControllerType::DualJoyconDetached; @@ -106,7 +106,7 @@ void EmulatedController::ReloadFromSettings() { SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); original_npad_type = npad_type; } else { - SetNpadStyleIndex(NpadStyleIndex::ProController); + SetNpadStyleIndex(NpadStyleIndex::Fullkey); original_npad_type = npad_type; } @@ -1073,7 +1073,7 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback .body = GetNpadColor(controller.color_values[index].body), .button = GetNpadColor(controller.color_values[index].buttons), }; - if (npad_type == NpadStyleIndex::ProController) { + if (npad_type == NpadStyleIndex::Fullkey) { controller.colors_state.left = { .body = GetNpadColor(controller.color_values[index].left_grip), .button = GetNpadColor(controller.color_values[index].buttons), @@ -1356,7 +1356,7 @@ bool EmulatedController::HasNfc() const { switch (npad_type) { case NpadStyleIndex::JoyconRight: case NpadStyleIndex::JoyconDual: - case NpadStyleIndex::ProController: + case NpadStyleIndex::Fullkey: case NpadStyleIndex::Handheld: break; default: @@ -1548,7 +1548,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) // Fallback Fullkey controllers to Pro controllers if (IsControllerFullkey() && supported_style_tag.fullkey) { LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); - SetNpadStyleIndex(NpadStyleIndex::ProController); + SetNpadStyleIndex(NpadStyleIndex::Fullkey); Connect(); return; } @@ -1556,13 +1556,13 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) // Fallback Dual joycon controllers to Pro controllers if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) { LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); - SetNpadStyleIndex(NpadStyleIndex::ProController); + SetNpadStyleIndex(NpadStyleIndex::Fullkey); Connect(); return; } // Fallback Pro controllers to Dual joycon - if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) { + if (npad_type == NpadStyleIndex::Fullkey && supported_style_tag.joycon_dual) { LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type); SetNpadStyleIndex(NpadStyleIndex::JoyconDual); Connect(); @@ -1577,7 +1577,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { std::scoped_lock lock{mutex}; const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; switch (type) { - case NpadStyleIndex::ProController: + case NpadStyleIndex::Fullkey: case NpadStyleIndex::GameCube: case NpadStyleIndex::NES: case NpadStyleIndex::SNES: @@ -1593,7 +1593,7 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { std::scoped_lock lock{mutex}; const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; switch (type) { - case NpadStyleIndex::ProController: + case NpadStyleIndex::Fullkey: return supported_style_tag.fullkey.As<bool>(); case NpadStyleIndex::Handheld: return supported_style_tag.handheld.As<bool>(); diff --git a/src/hid_core/hid_types.h b/src/hid_core/hid_types.h index a81ed6af0..2c3f02f34 100644 --- a/src/hid_core/hid_types.h +++ b/src/hid_core/hid_types.h @@ -220,6 +220,7 @@ enum class NpadIdType : u32 { }; enum class NpadInterfaceType : u8 { + None = 0, Bluetooth = 1, Rail = 2, Usb = 3, @@ -229,7 +230,7 @@ enum class NpadInterfaceType : u8 { // This is nn::hid::NpadStyleIndex enum class NpadStyleIndex : u8 { None = 0, - ProController = 3, + Fullkey = 3, Handheld = 4, HandheldNES = 4, JoyconDual = 5, diff --git a/src/hid_core/hid_util.h b/src/hid_core/hid_util.h index 94ff2d23a..397a87472 100644 --- a/src/hid_core/hid_util.h +++ b/src/hid_core/hid_util.h @@ -42,7 +42,7 @@ constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& hand constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) { switch (handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::JoyconLeft: diff --git a/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp new file mode 100644 index 000000000..62fbbb0a7 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp @@ -0,0 +1,197 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/core_timing.h" +#include "hid_core/hid_result.h" +#include "hid_core/hid_util.h" +#include "hid_core/resources/abstracted_pad/abstract_battery_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/shared_memory_format.h" + +namespace Service::HID { + +NpadAbstractBatteryHandler::NpadAbstractBatteryHandler() {} + +NpadAbstractBatteryHandler::~NpadAbstractBatteryHandler() = default; + +void NpadAbstractBatteryHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractBatteryHandler::SetAppletResource(AppletResourceHolder* applet_resource) { + applet_resource_holder = applet_resource; +} + +void NpadAbstractBatteryHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; +} + +Result NpadAbstractBatteryHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractBatteryHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +Result NpadAbstractBatteryHandler::UpdateBatteryState(u64 aruid) { + const auto npad_index = NpadIdTypeToIndex(properties_handler->GetNpadId()); + AruidData* aruid_data = applet_resource_holder->applet_resource->GetAruidData(aruid); + if (aruid_data == nullptr) { + return ResultSuccess; + } + + auto& npad_internal_state = + aruid_data->shared_memory_format->npad.npad_entry[npad_index].internal_state; + auto& system_properties = npad_internal_state.system_properties; + + system_properties.is_charging_joy_dual.Assign(dual_battery.is_charging); + system_properties.is_powered_joy_dual.Assign(dual_battery.is_powered); + system_properties.is_charging_joy_left.Assign(left_battery.is_charging); + system_properties.is_powered_joy_left.Assign(left_battery.is_powered); + system_properties.is_charging_joy_right.Assign(right_battery.is_charging); + system_properties.is_powered_joy_right.Assign(right_battery.is_powered); + + npad_internal_state.battery_level_dual = dual_battery.battery_level; + npad_internal_state.battery_level_left = left_battery.battery_level; + npad_internal_state.battery_level_right = right_battery.battery_level; + + return ResultSuccess; +} + +void NpadAbstractBatteryHandler::UpdateBatteryState() { + if (ref_counter == 0) { + return; + } + has_new_battery_data = GetNewBatteryState(); +} + +bool NpadAbstractBatteryHandler::GetNewBatteryState() { + bool has_changed = false; + Core::HID::NpadPowerInfo new_dual_battery_state{}; + Core::HID::NpadPowerInfo new_left_battery_state{}; + Core::HID::NpadPowerInfo new_right_battery_state{}; + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + const auto power_info = abstract_pad->power_info; + if (power_info.battery_level > Core::HID::NpadBatteryLevel::Full) { + // Abort + continue; + } + + const auto style = abstract_pad->assignment_style; + + if (style.is_external_assigned || style.is_handheld_assigned) { + new_dual_battery_state = power_info; + } + if (style.is_external_left_assigned || style.is_handheld_left_assigned) { + new_left_battery_state = power_info; + } + if (style.is_external_right_assigned || style.is_handheld_right_assigned) { + new_right_battery_state = power_info; + } + + if (abstract_pad->internal_flags.is_battery_low_ovln_required) { + if (abstract_pad->interface_type == Core::HID::NpadInterfaceType::Rail) { + // TODO + } + abstract_pad->internal_flags.is_battery_low_ovln_required.Assign(false); + } + } + + if (dual_battery.battery_level != new_dual_battery_state.battery_level || + dual_battery.is_charging != new_dual_battery_state.is_charging || + dual_battery.is_powered != new_dual_battery_state.is_powered) { + has_changed = true; + dual_battery = new_dual_battery_state; + } + + if (left_battery.battery_level != new_left_battery_state.battery_level || + left_battery.is_charging != new_left_battery_state.is_charging || + left_battery.is_powered != new_left_battery_state.is_powered) { + has_changed = true; + left_battery = new_left_battery_state; + } + + if (right_battery.battery_level != new_right_battery_state.battery_level || + right_battery.is_charging != new_right_battery_state.is_charging || + right_battery.is_powered != new_right_battery_state.is_powered) { + has_changed = true; + right_battery = new_right_battery_state; + } + + return has_changed; +} + +void NpadAbstractBatteryHandler::UpdateCoreBatteryState() { + if (ref_counter == 0) { + return; + } + if (!has_new_battery_data) { + return; + } + + UpdateBatteryState(0); +} + +void NpadAbstractBatteryHandler::InitializeBatteryState(u64 aruid) { + UpdateBatteryState(aruid); +} + +bool NpadAbstractBatteryHandler::HasBattery() const { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + for (std::size_t i = 0; i < count; i++) { + const auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + return abstract_pad->disabled_feature_set.has_fullkey_battery || + abstract_pad->disabled_feature_set.has_left_right_joy_battery; + } + + return false; +} + +void NpadAbstractBatteryHandler::HasLeftRightBattery(bool& has_left, bool& has_right) const { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + has_left = false; + has_right = false; + + for (std::size_t i = 0; i < count; i++) { + const auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + if (!abstract_pad->disabled_feature_set.has_fullkey_battery && + !abstract_pad->disabled_feature_set.has_left_right_joy_battery) { + continue; + } + has_left = abstract_pad->assignment_style.is_external_left_assigned || + abstract_pad->assignment_style.is_handheld_left_assigned; + has_right = abstract_pad->assignment_style.is_external_right_assigned || + abstract_pad->assignment_style.is_handheld_right_assigned; + } +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h new file mode 100644 index 000000000..85ac5eb72 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Service::HID { +struct AppletResourceHolder; +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; + +/// Handles Npad request from HID interfaces +class NpadAbstractBatteryHandler final { +public: + explicit NpadAbstractBatteryHandler(); + ~NpadAbstractBatteryHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetAppletResource(AppletResourceHolder* applet_resource); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + Result UpdateBatteryState(u64 aruid); + void UpdateBatteryState(); + bool GetNewBatteryState(); + void UpdateCoreBatteryState(); + void InitializeBatteryState(u64 aruid); + + bool HasBattery() const; + void HasLeftRightBattery(bool& has_left, bool& has_right) const; + +private: + AppletResourceHolder* applet_resource_holder{nullptr}; + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + + s32 ref_counter{}; + Core::HID::NpadPowerInfo dual_battery{}; + Core::HID::NpadPowerInfo left_battery{}; + Core::HID::NpadPowerInfo right_battery{}; + bool has_new_battery_data{}; +}; + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp new file mode 100644 index 000000000..587169433 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp @@ -0,0 +1,199 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/hid_util.h" +#include "hid_core/resources/abstracted_pad/abstract_button_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/npad/npad_resource.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/shared_memory_format.h" + +namespace Service::HID { + +NpadAbstractButtonHandler::NpadAbstractButtonHandler() {} + +NpadAbstractButtonHandler::~NpadAbstractButtonHandler() = default; + +void NpadAbstractButtonHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractButtonHandler::SetAppletResource(AppletResourceHolder* applet_resource) { + applet_resource_holder = applet_resource; +} + +void NpadAbstractButtonHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; +} + +Result NpadAbstractButtonHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractButtonHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +Result NpadAbstractButtonHandler::UpdateAllButtonWithHomeProtection(u64 aruid) { + const Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); + auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid); + + if (data == nullptr) { + return ResultSuccess; + } + + auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; + UpdateButtonLifo(npad_entry, aruid); + + bool is_home_button_protection_enabled{}; + const auto result = applet_resource_holder->shared_npad_resource->GetHomeProtectionEnabled( + is_home_button_protection_enabled, aruid, npad_id); + + if (result.IsError()) { + return ResultSuccess; + } + + npad_entry.internal_state.button_properties.is_home_button_protection_enabled.Assign( + is_home_button_protection_enabled); + + return ResultSuccess; +} + +void NpadAbstractButtonHandler::UpdateAllButtonLifo() { + Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); + for (std::size_t i = 0; i < AruidIndexMax; i++) { + auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i); + auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; + UpdateButtonLifo(npad_entry, data->aruid); + } +} + +void NpadAbstractButtonHandler::UpdateCoreBatteryState() { + Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); + for (std::size_t i = 0; i < AruidIndexMax; i++) { + auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i); + auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; + UpdateButtonLifo(npad_entry, data->aruid); + } +} + +void NpadAbstractButtonHandler::UpdateButtonState(u64 aruid) { + Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); + auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid); + if (data == nullptr) { + return; + } + auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; + UpdateButtonLifo(npad_entry, aruid); +} + +Result NpadAbstractButtonHandler::SetHomeProtection(bool is_enabled, u64 aruid) { + const Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); + auto result = applet_resource_holder->shared_npad_resource->SetHomeProtectionEnabled( + aruid, npad_id, is_enabled); + if (result.IsError()) { + return result; + } + + auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid); + if (data == nullptr) { + return ResultSuccess; + } + + bool is_home_protection_enabled{}; + result = applet_resource_holder->shared_npad_resource->GetHomeProtectionEnabled( + is_home_protection_enabled, aruid, npad_id); + if (result.IsError()) { + return ResultSuccess; + } + + auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; + npad_entry.internal_state.button_properties.is_home_button_protection_enabled.Assign( + is_home_protection_enabled); + return ResultSuccess; +} + +bool NpadAbstractButtonHandler::IsButtonPressedOnConsoleMode() { + return is_button_pressed_on_console_mode; +} + +void NpadAbstractButtonHandler::EnableCenterClamp() { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + abstract_pad->internal_flags.use_center_clamp.Assign(true); + } +} + +void NpadAbstractButtonHandler::UpdateButtonLifo(NpadSharedMemoryEntry& shared_memory, u64 aruid) { + auto* npad_resource = applet_resource_holder->shared_npad_resource; + Core::HID::NpadStyleTag style_tag = {properties_handler->GetStyleSet(aruid)}; + style_tag.system_ext.Assign(npad_resource->GetActiveData()->GetNpadSystemExtState()); + + UpdateNpadFullkeyLifo(style_tag, 0, aruid, shared_memory); + UpdateHandheldLifo(style_tag, 1, aruid, shared_memory); + UpdateJoyconDualLifo(style_tag, 2, aruid, shared_memory); + UpdateJoyconLeftLifo(style_tag, 3, aruid, shared_memory); + UpdateJoyconRightLifo(style_tag, 4, aruid, shared_memory); + UpdatePalmaLifo(style_tag, 5, aruid, shared_memory); + UpdateSystemExtLifo(style_tag, 6, aruid, shared_memory); +} + +void NpadAbstractButtonHandler::UpdateNpadFullkeyLifo(Core::HID::NpadStyleTag style_tag, + int style_index, u64 aruid, + NpadSharedMemoryEntry& shared_memory) { + // TODO +} + +void NpadAbstractButtonHandler::UpdateHandheldLifo(Core::HID::NpadStyleTag style_tag, + int style_index, u64 aruid, + NpadSharedMemoryEntry& shared_memory) { + // TODO +} + +void NpadAbstractButtonHandler::UpdateJoyconDualLifo(Core::HID::NpadStyleTag style_tag, + int style_index, u64 aruid, + NpadSharedMemoryEntry& shared_memory) { + // TODO +} + +void NpadAbstractButtonHandler::UpdateJoyconLeftLifo(Core::HID::NpadStyleTag style_tag, + int style_index, u64 aruid, + NpadSharedMemoryEntry& shared_memory) { + // TODO +} + +void NpadAbstractButtonHandler::UpdateJoyconRightLifo(Core::HID::NpadStyleTag style_tag, + int style_index, u64 aruid, + NpadSharedMemoryEntry& shared_memory) { + // TODO +} + +void NpadAbstractButtonHandler::UpdateSystemExtLifo(Core::HID::NpadStyleTag style_tag, + int style_index, u64 aruid, + NpadSharedMemoryEntry& shared_memory) { + // TODO +} + +void NpadAbstractButtonHandler::UpdatePalmaLifo(Core::HID::NpadStyleTag style_tag, int style_index, + u64 aruid, NpadSharedMemoryEntry& shared_memory) { + // TODO +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_button_handler.h b/src/hid_core/resources/abstracted_pad/abstract_button_handler.h new file mode 100644 index 000000000..01eafe96d --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_button_handler.h @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Service::HID { +struct NpadSharedMemoryEntry; + +struct AppletResourceHolder; +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; + +/// Handles Npad request from HID interfaces +class NpadAbstractButtonHandler final { +public: + explicit NpadAbstractButtonHandler(); + ~NpadAbstractButtonHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetAppletResource(AppletResourceHolder* applet_resource); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + Result UpdateAllButtonWithHomeProtection(u64 aruid); + + void UpdateAllButtonLifo(); + void UpdateCoreBatteryState(); + void UpdateButtonState(u64 aruid); + + Result SetHomeProtection(bool is_enabled, u64 aruid); + bool IsButtonPressedOnConsoleMode(); + void EnableCenterClamp(); + + void UpdateButtonLifo(NpadSharedMemoryEntry& shared_memory, u64 aruid); + + void UpdateNpadFullkeyLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, + NpadSharedMemoryEntry& shared_memory); + void UpdateHandheldLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, + NpadSharedMemoryEntry& shared_memory); + void UpdateJoyconDualLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, + NpadSharedMemoryEntry& shared_memory); + void UpdateJoyconLeftLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, + NpadSharedMemoryEntry& shared_memory); + void UpdateJoyconRightLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, + NpadSharedMemoryEntry& shared_memory); + void UpdateSystemExtLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, + NpadSharedMemoryEntry& shared_memory); + void UpdatePalmaLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid, + NpadSharedMemoryEntry& shared_memory); + +private: + struct GcTrigger { + float left; + float right; + }; + + AppletResourceHolder* applet_resource_holder{nullptr}; + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + + s32 ref_counter{}; + + bool is_button_pressed_on_console_mode{}; + + u64 gc_sampling_number{}; + GcTrigger gc_trigger_state{}; +}; + +} // namespace Service::HID 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 new file mode 100644 index 000000000..d4e4181bf --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp @@ -0,0 +1,126 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "hid_core/hid_result.h" +#include "hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/npad/npad_types.h" + +namespace Service::HID { + +NpadAbstractIrSensorHandler::NpadAbstractIrSensorHandler() {} + +NpadAbstractIrSensorHandler::~NpadAbstractIrSensorHandler() = default; + +void NpadAbstractIrSensorHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractIrSensorHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; +} + +Result NpadAbstractIrSensorHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractIrSensorHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +void NpadAbstractIrSensorHandler::UpdateIrSensorState() { + const auto previous_state = sensor_state; + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + if (count == 0) { + sensor_state = NpadIrSensorState::Disabled; + if (sensor_state == previous_state) { + return; + } + ir_sensor_event->Signal(); + return; + } + + bool is_found{}; + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + if (!abstract_pad->disabled_feature_set.has_bluetooth_address) { + continue; + } + is_found = true; + xcd_handle = abstract_pad->xcd_handle; + } + + if (is_found) { + if (sensor_state == NpadIrSensorState::Active) { + return; + } + sensor_state = NpadIrSensorState::Available; + if (sensor_state == previous_state) { + return; + } + ir_sensor_event->Signal(); + return; + } + + sensor_state = NpadIrSensorState::Unavailable; + if (sensor_state == previous_state) { + return; + } + + ir_sensor_event->Signal(); + return; +} + +Result NpadAbstractIrSensorHandler::ActivateIrSensor(bool is_enabled) { + if (sensor_state == NpadIrSensorState::Unavailable) { + return ResultIrSensorIsNotReady; + } + if (is_enabled && sensor_state == NpadIrSensorState::Available) { + sensor_state = NpadIrSensorState::Active; + } else { + if (is_enabled) { + return ResultSuccess; + } + if (sensor_state != NpadIrSensorState::Active) { + return ResultSuccess; + } + sensor_state = NpadIrSensorState::Available; + } + ir_sensor_event->Signal(); + return ResultSuccess; +} + +Result NpadAbstractIrSensorHandler::GetIrSensorEventHandle(Kernel::KReadableEvent** out_event) { + *out_event = &ir_sensor_event->GetReadableEvent(); + return ResultSuccess; +} + +Result NpadAbstractIrSensorHandler::GetXcdHandleForNpadWithIrSensor(u64& handle) const { + if (sensor_state < NpadIrSensorState::Available) { + return ResultIrSensorIsNotReady; + } + handle = xcd_handle; + return ResultSuccess; +} + +NpadIrSensorState NpadAbstractIrSensorHandler::GetSensorState() const { + return sensor_state; +} + +} // namespace Service::HID 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 new file mode 100644 index 000000000..fe8e005af --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +enum class NpadIrSensorState : u32 { + Disabled, + Unavailable, + Available, + Active, +}; + +namespace Service::HID { +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; + +/// Handles Npad request from HID interfaces +class NpadAbstractIrSensorHandler final { +public: + explicit NpadAbstractIrSensorHandler(); + ~NpadAbstractIrSensorHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + void UpdateIrSensorState(); + Result ActivateIrSensor(bool param_2); + + Result GetIrSensorEventHandle(Kernel::KReadableEvent** out_event); + + Result GetXcdHandleForNpadWithIrSensor(u64& handle) const; + + NpadIrSensorState GetSensorState() const; + +private: + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + + s32 ref_counter{}; + Kernel::KEvent* ir_sensor_event{nullptr}; + u64 xcd_handle{}; + NpadIrSensorState sensor_state{}; +}; +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp new file mode 100644 index 000000000..0b2bfe88d --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp @@ -0,0 +1,123 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/core_timing.h" +#include "hid_core/hid_result.h" +#include "hid_core/hid_util.h" +#include "hid_core/resources/abstracted_pad/abstract_led_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/npad/npad_types.h" + +namespace Service::HID { + +NpadAbstractLedHandler::NpadAbstractLedHandler() {} + +NpadAbstractLedHandler::~NpadAbstractLedHandler() = default; + +void NpadAbstractLedHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractLedHandler::SetAppletResource(AppletResourceHolder* applet_resource) { + applet_resource_holder = applet_resource; +} + +void NpadAbstractLedHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; +} + +Result NpadAbstractLedHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractLedHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +void NpadAbstractLedHandler::SetNpadLedHandlerLedPattern() { + const auto npad_id = properties_handler->GetNpadId(); + + switch (npad_id) { + case Core::HID::NpadIdType::Player1: + left_pattern = Core::HID::LedPattern{1, 0, 0, 0}; + break; + case Core::HID::NpadIdType::Player2: + left_pattern = Core::HID::LedPattern{1, 1, 0, 0}; + break; + case Core::HID::NpadIdType::Player3: + left_pattern = Core::HID::LedPattern{1, 1, 1, 0}; + break; + case Core::HID::NpadIdType::Player4: + left_pattern = Core::HID::LedPattern{1, 1, 1, 1}; + break; + case Core::HID::NpadIdType::Player5: + left_pattern = Core::HID::LedPattern{1, 0, 0, 1}; + break; + case Core::HID::NpadIdType::Player6: + left_pattern = Core::HID::LedPattern{1, 0, 1, 0}; + break; + case Core::HID::NpadIdType::Player7: + left_pattern = Core::HID::LedPattern{1, 0, 1, 1}; + break; + case Core::HID::NpadIdType::Player8: + left_pattern = Core::HID::LedPattern{0, 1, 1, 0}; + break; + case Core::HID::NpadIdType::Other: + case Core::HID::NpadIdType::Handheld: + left_pattern = Core::HID::LedPattern{0, 0, 0, 0}; + break; + default: + ASSERT_MSG(false, "Invalid npad id type"); + break; + } + + switch (npad_id) { + case Core::HID::NpadIdType::Player1: + right_pattern = Core::HID::LedPattern{0, 0, 0, 1}; + break; + case Core::HID::NpadIdType::Player2: + right_pattern = Core::HID::LedPattern{0, 1, 1, 1}; + break; + case Core::HID::NpadIdType::Player3: + right_pattern = Core::HID::LedPattern{0, 1, 1, 1}; + break; + case Core::HID::NpadIdType::Player4: + right_pattern = Core::HID::LedPattern{1, 1, 1, 1}; + break; + case Core::HID::NpadIdType::Player5: + right_pattern = Core::HID::LedPattern{1, 0, 0, 1}; + break; + case Core::HID::NpadIdType::Player6: + right_pattern = Core::HID::LedPattern{0, 1, 0, 1}; + break; + case Core::HID::NpadIdType::Player7: + right_pattern = Core::HID::LedPattern{1, 1, 0, 1}; + break; + case Core::HID::NpadIdType::Player8: + right_pattern = Core::HID::LedPattern{0, 1, 1, 0}; + break; + case Core::HID::NpadIdType::Other: + case Core::HID::NpadIdType::Handheld: + right_pattern = Core::HID::LedPattern{0, 0, 0, 0}; + break; + default: + ASSERT_MSG(false, "Invalid npad id type"); + break; + } +} + +void NpadAbstractLedHandler::SetLedBlinkingDevice(Core::HID::LedPattern pattern) { + led_blinking = pattern; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_led_handler.h b/src/hid_core/resources/abstracted_pad/abstract_led_handler.h new file mode 100644 index 000000000..09528129b --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_led_handler.h @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Service::HID { +struct AppletResourceHolder; +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; + +/// Handles Npad request from HID interfaces +class NpadAbstractLedHandler final { +public: + explicit NpadAbstractLedHandler(); + ~NpadAbstractLedHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetAppletResource(AppletResourceHolder* applet_resource); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + void SetNpadLedHandlerLedPattern(); + + void SetLedBlinkingDevice(Core::HID::LedPattern pattern); + +private: + AppletResourceHolder* applet_resource_holder{nullptr}; + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + + s32 ref_counter{}; + Core::HID::LedPattern led_blinking{0, 0, 0, 0}; + Core::HID::LedPattern left_pattern{0, 0, 0, 0}; + Core::HID::LedPattern right_pattern{0, 0, 0, 0}; + u64 led_interval{}; +}; +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp new file mode 100644 index 000000000..6f35bd95c --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/abstracted_pad/abstract_mcu_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/npad/npad_types.h" + +namespace Service::HID { + +NpadAbstractMcuHandler::NpadAbstractMcuHandler() {} + +NpadAbstractMcuHandler::~NpadAbstractMcuHandler() = default; + +void NpadAbstractMcuHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractMcuHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; +} + +Result NpadAbstractMcuHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractMcuHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +void NpadAbstractMcuHandler::UpdateMcuState() { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = properties_handler->GetAbstractedPads(abstract_pads); + + if (count == 0) { + mcu_holder = {}; + return; + } + + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + if (!abstract_pad->disabled_feature_set.has_left_joy_rail_bus) { + if (!abstract_pad->disabled_feature_set.has_left_joy_six_axis_sensor && + !abstract_pad->disabled_feature_set.has_right_joy_six_axis_sensor) { + continue; + } + if (mcu_holder[1].state != NpadMcuState::Active) { + mcu_holder[1].state = NpadMcuState::Available; + } + mcu_holder[1].abstracted_pad = abstract_pad; + continue; + } + if (mcu_holder[0].state != NpadMcuState::Active) { + mcu_holder[0].state = NpadMcuState::Available; + } + mcu_holder[0].abstracted_pad = abstract_pad; + } +} + +Result NpadAbstractMcuHandler::GetAbstractedPad(IAbstractedPad** data, u32 mcu_index) { + if (mcu_holder[mcu_index].state == NpadMcuState::None || + mcu_holder[mcu_index].abstracted_pad == nullptr) { + return ResultMcuIsNotReady; + } + *data = mcu_holder[mcu_index].abstracted_pad; + return ResultSuccess; +} + +NpadMcuState NpadAbstractMcuHandler::GetMcuState(u32 mcu_index) { + return mcu_holder[mcu_index].state; +} + +Result NpadAbstractMcuHandler::SetMcuState(bool is_enabled, u32 mcu_index) { + NpadMcuState& state = mcu_holder[mcu_index].state; + + if (state == NpadMcuState::None) { + return ResultMcuIsNotReady; + } + + if ((is_enabled) && (state == NpadMcuState::Available)) { + state = NpadMcuState::Active; + return ResultSuccess; + } + + if (is_enabled) { + return ResultSuccess; + } + if (state != NpadMcuState::Active) { + return ResultSuccess; + } + + state = NpadMcuState::Available; + return ResultSuccess; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h new file mode 100644 index 000000000..9902dd03a --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Service::HID { +struct IAbstractedPad; +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; + +enum class NpadMcuState : u32 { + None, + Available, + Active, +}; + +struct NpadMcuHolder { + NpadMcuState state; + INSERT_PADDING_BYTES(0x4); + IAbstractedPad* abstracted_pad; +}; +static_assert(sizeof(NpadMcuHolder) == 0x10, "NpadMcuHolder is an invalid size"); + +/// Handles Npad request from HID interfaces +class NpadAbstractMcuHandler final { +public: + explicit NpadAbstractMcuHandler(); + ~NpadAbstractMcuHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + void UpdateMcuState(); + Result GetAbstractedPad(IAbstractedPad** data, u32 mcu_index); + NpadMcuState GetMcuState(u32 mcu_index); + Result SetMcuState(bool is_enabled, u32 mcu_index); + +private: + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + + s32 ref_counter{}; + std::array<NpadMcuHolder, 2> mcu_holder{}; +}; +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp new file mode 100644 index 000000000..bd9b79333 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp @@ -0,0 +1,140 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "hid_core/hid_result.h" +#include "hid_core/resources/abstracted_pad/abstract_nfc_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/npad/npad_types.h" + +namespace Service::HID { + +NpadAbstractNfcHandler::NpadAbstractNfcHandler() {} + +NpadAbstractNfcHandler::~NpadAbstractNfcHandler() = default; + +void NpadAbstractNfcHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractNfcHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; +} + +Result NpadAbstractNfcHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractNfcHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +void NpadAbstractNfcHandler::UpdateNfcState() { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = properties_handler->GetAbstractedPads(abstract_pads); + + if (count == 0) { + if (sensor_state == NpadNfcState::Active) { + nfc_activate_event->Signal(); + } + if (sensor_state == NpadNfcState::Unavailable) { + return; + } + sensor_state = NpadNfcState::Unavailable; + input_event->Signal(); + return; + } + + bool is_found{}; + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + if (!abstract_pad->disabled_feature_set.has_nfc) { + continue; + } + is_found = true; + xcd_handle = 0; + } + + if (is_found) { + if (sensor_state == NpadNfcState::Active) { + return; + } + if (sensor_state == NpadNfcState::Available) { + return; + } + sensor_state = NpadNfcState::Available; + input_event->Signal(); + return; + } + + if (sensor_state == NpadNfcState::Active) { + nfc_activate_event->Signal(); + } + if (sensor_state == NpadNfcState::Unavailable) { + return; + } + sensor_state = NpadNfcState::Unavailable; + input_event->Signal(); + return; +} + +bool NpadAbstractNfcHandler::HasNfcSensor() { + return sensor_state != NpadNfcState::Unavailable; +} + +bool NpadAbstractNfcHandler::IsNfcActivated() { + return sensor_state == NpadNfcState::Active; +} + +Result NpadAbstractNfcHandler::GetAcquireNfcActivateEventHandle( + Kernel::KReadableEvent** out_event) { + *out_event = &nfc_activate_event->GetReadableEvent(); + return ResultSuccess; +} + +void NpadAbstractNfcHandler::SetInputEvent(Kernel::KEvent* event) { + input_event = event; +} + +Result NpadAbstractNfcHandler::ActivateNfc(bool is_enabled) { + if (sensor_state == NpadNfcState::Active) { + return ResultNfcIsNotReady; + } + + NpadNfcState new_state = NpadNfcState::Available; + if (is_enabled) { + new_state = NpadNfcState::Active; + } + if (sensor_state != new_state) { + sensor_state = new_state; + nfc_activate_event->Signal(); + } + return ResultSuccess; +} + +Result NpadAbstractNfcHandler::GetXcdHandleWithNfc(u64& out_xcd_handle) const { + if (sensor_state == NpadNfcState::Unavailable) { + return ResultNfcIsNotReady; + } + if (xcd_handle == 0) { + return ResultNfcXcdHandleIsNotInitialized; + } + + out_xcd_handle = xcd_handle; + return ResultSuccess; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h new file mode 100644 index 000000000..0702722a6 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Kernel { +class KReadableEvent; +} + +enum class NpadNfcState : u32 { + Unavailable, + Available, + Active, +}; + +namespace Service::HID { +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; + +/// Handles Npad request from HID interfaces +class NpadAbstractNfcHandler final { +public: + explicit NpadAbstractNfcHandler(); + ~NpadAbstractNfcHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + void UpdateNfcState(); + bool HasNfcSensor(); + bool IsNfcActivated(); + + Result GetAcquireNfcActivateEventHandle(Kernel::KReadableEvent** out_event); + void SetInputEvent(Kernel::KEvent* event); + + Result ActivateNfc(bool is_enabled); + + Result GetXcdHandleWithNfc(u64& out_xcd_handle) const; + +private: + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + + s32 ref_counter{}; + Kernel::KEvent* nfc_activate_event{nullptr}; + Kernel::KEvent* input_event{nullptr}; + u64 xcd_handle{}; + NpadNfcState sensor_state{NpadNfcState::Unavailable}; +}; +} // 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 new file mode 100644 index 000000000..2c7691d7c --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp @@ -0,0 +1,294 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/abstracted_pad/abstract_pad.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/npad/npad_types.h" + +namespace Service::HID { + +AbstractPad::AbstractPad() {} + +AbstractPad::~AbstractPad() = default; + +void AbstractPad::SetExternals(AppletResourceHolder* applet_resource, + CaptureButtonResource* capture_button_resource, + HomeButtonResource* home_button_resource, + SixAxisResource* sixaxis_resource, PalmaResource* palma_resource, + VibrationHandler* vibration) { + applet_resource_holder = applet_resource; + + properties_handler.SetAppletResource(applet_resource_holder); + properties_handler.SetAbstractPadHolder(&abstract_pad_holder); + + led_handler.SetAppletResource(applet_resource_holder); + led_handler.SetAbstractPadHolder(&abstract_pad_holder); + led_handler.SetPropertiesHandler(&properties_handler); + + ir_sensor_handler.SetAbstractPadHolder(&abstract_pad_holder); + ir_sensor_handler.SetPropertiesHandler(&properties_handler); + + nfc_handler.SetAbstractPadHolder(&abstract_pad_holder); + nfc_handler.SetPropertiesHandler(&properties_handler); + + mcu_handler.SetAbstractPadHolder(&abstract_pad_holder); + mcu_handler.SetPropertiesHandler(&properties_handler); + + std::array<NpadVibrationDevice*, 2> vibration_devices{&vibration_left, &vibration_right}; + vibration_handler.SetAppletResource(applet_resource_holder); + vibration_handler.SetAbstractPadHolder(&abstract_pad_holder); + vibration_handler.SetPropertiesHandler(&properties_handler); + vibration_handler.SetN64Vibration(&vibration_n64); + vibration_handler.SetVibration(vibration_devices); + vibration_handler.SetGcVibration(&vibration_gc); + + sixaxis_handler.SetAppletResource(applet_resource_holder); + sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder); + sixaxis_handler.SetPropertiesHandler(&properties_handler); + sixaxis_handler.SetSixaxisResource(sixaxis_resource); + + button_handler.SetAppletResource(applet_resource_holder); + button_handler.SetAbstractPadHolder(&abstract_pad_holder); + button_handler.SetPropertiesHandler(&properties_handler); + + battery_handler.SetAppletResource(applet_resource_holder); + battery_handler.SetAbstractPadHolder(&abstract_pad_holder); + battery_handler.SetPropertiesHandler(&properties_handler); + + palma_handler.SetAbstractPadHolder(&abstract_pad_holder); + palma_handler.SetPropertiesHandler(&properties_handler); + palma_handler.SetPalmaResource(palma_resource); +} + +void AbstractPad::SetNpadId(Core::HID::NpadIdType npad_id) { + properties_handler.SetNpadId(npad_id); +} + +Result AbstractPad::Activate() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + + if (ref_counter != 0) { + ref_counter++; + return ResultSuccess; + } + + std::size_t stage = 0; + Result result = ResultSuccess; + + if (result.IsSuccess()) { + stage++; + result = properties_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = led_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = ir_sensor_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = mcu_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = nfc_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = vibration_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = sixaxis_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = button_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = battery_handler.IncrementRefCounter(); + } + if (result.IsSuccess()) { + stage++; + result = palma_handler.IncrementRefCounter(); + } + + if (result.IsSuccess()) { + ref_counter++; + return result; + } + + if (stage > 9) { + battery_handler.DecrementRefCounter(); + } + if (stage > 8) { + button_handler.DecrementRefCounter(); + } + if (stage > 7) { + sixaxis_handler.DecrementRefCounter(); + } + if (stage > 6) { + vibration_handler.DecrementRefCounter(); + } + if (stage > 5) { + nfc_handler.DecrementRefCounter(); + } + if (stage > 4) { + mcu_handler.DecrementRefCounter(); + } + if (stage > 3) { + ir_sensor_handler.DecrementRefCounter(); + } + if (stage > 2) { + led_handler.DecrementRefCounter(); + } + if (stage > 1) { + properties_handler.DecrementRefCounter(); + } + return result; +} + +Result AbstractPad::Deactivate() { + if (ref_counter == 0) { + return ResultNpadResourceNotInitialized; + } + + ref_counter--; + battery_handler.DecrementRefCounter(); + button_handler.DecrementRefCounter(); + sixaxis_handler.DecrementRefCounter(); + vibration_handler.DecrementRefCounter(); + nfc_handler.DecrementRefCounter(); + ir_sensor_handler.DecrementRefCounter(); + mcu_handler.DecrementRefCounter(); + led_handler.DecrementRefCounter(); + properties_handler.DecrementRefCounter(); + palma_handler.DecrementRefCounter(); + + return ResultSuccess; +} + +Result AbstractPad::ActivateNpad(u64 aruid) { + Result result = ResultSuccess; + if (result.IsSuccess()) { + result = properties_handler.ActivateNpadUnknown0x88(aruid); + } + if (result.IsSuccess()) { + result = sixaxis_handler.UpdateSixAxisState2(aruid); + } + if (result.IsSuccess()) { + result = battery_handler.UpdateBatteryState(aruid); + } + return result; +} + +NpadAbstractedPadHolder* AbstractPad::GetAbstractedPadHolder() { + return &abstract_pad_holder; +} + +NpadAbstractPropertiesHandler* AbstractPad::GetAbstractPropertiesHandler() { + return &properties_handler; +} + +NpadAbstractLedHandler* AbstractPad::GetAbstractLedHandler() { + return &led_handler; +} + +NpadAbstractIrSensorHandler* AbstractPad::GetAbstractIrSensorHandler() { + return &ir_sensor_handler; +} + +NpadAbstractMcuHandler* AbstractPad::GetAbstractMcuHandler() { + return &mcu_handler; +} + +NpadAbstractNfcHandler* AbstractPad::GetAbstractNfcHandler() { + return &nfc_handler; +} + +NpadAbstractVibrationHandler* AbstractPad::GetAbstractVibrationHandler() { + return &vibration_handler; +} + +NpadAbstractSixAxisHandler* AbstractPad::GetAbstractSixAxisHandler() { + return &sixaxis_handler; +} + +NpadAbstractButtonHandler* AbstractPad::GetAbstractButtonHandler() { + return &button_handler; +} + +NpadAbstractBatteryHandler* AbstractPad::GetAbstractBatteryHandler() { + return &battery_handler; +} + +NpadN64VibrationDevice* AbstractPad::GetN64VibrationDevice() { + return &vibration_n64; +} + +NpadVibrationDevice* AbstractPad::GetVibrationDevice(Core::HID::DeviceIndex device_index) { + if (device_index == Core::HID::DeviceIndex::Right) { + return &vibration_right; + } + return &vibration_left; +} + +void AbstractPad::GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list) { + list.emplace_back(&vibration_left); + list.emplace_back(&vibration_right); +} + +NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() { + return &vibration_gc; +} + +Core::HID::NpadIdType AbstractPad::GetLastActiveNpad() { + return properties_handler.GetNpadId(); +} + +void AbstractPad::UpdateInterfaceType() { + if (interface_type != properties_handler.GetInterfaceType()) { + Update(); + } + battery_handler.UpdateBatteryState(); +} + +void AbstractPad::Update() { + properties_handler.UpdateDeviceType(); + led_handler.SetNpadLedHandlerLedPattern(); + vibration_handler.UpdateVibrationState(); + sixaxis_handler.UpdateSixAxisState(); + nfc_handler.UpdateNfcState(); + ir_sensor_handler.UpdateIrSensorState(); + mcu_handler.UpdateMcuState(); + palma_handler.UpdatePalmaState(); + battery_handler.UpdateBatteryState(); + button_handler.EnableCenterClamp(); + + interface_type = properties_handler.GetInterfaceType(); + + std::scoped_lock lock{*applet_resource_holder->shared_mutex}; + properties_handler.UpdateAllDeviceProperties(); + battery_handler.UpdateCoreBatteryState(); + button_handler.UpdateCoreBatteryState(); +} + +void AbstractPad::UpdatePadState() { + button_handler.UpdateAllButtonLifo(); + sixaxis_handler.UpdateSixAxisState(); + battery_handler.UpdateCoreBatteryState(); +} + +void AbstractPad::EnableAppletToGetInput(u64 aruid) { + button_handler.UpdateButtonState(aruid); + sixaxis_handler.UpdateSixAxisState(aruid); + battery_handler.UpdateBatteryState(aruid); +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.h b/src/hid_core/resources/abstracted_pad/abstract_pad.h new file mode 100644 index 000000000..cbdf84af7 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_pad.h @@ -0,0 +1,123 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> +#include <mutex> + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/npad/npad_types.h" + +#include "hid_core/resources/abstracted_pad/abstract_battery_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_button_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_led_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_mcu_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_nfc_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_palma_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_vibration_handler.h" +#include "hid_core/resources/vibration/gc_vibration_device.h" +#include "hid_core/resources/vibration/n64_vibration_device.h" +#include "hid_core/resources/vibration/vibration_device.h" + +namespace Service::HID { +class AppletResource; +class SixAxisResource; +class PalmaResource; +class NPadResource; +class AbstractPad; +class NpadLastActiveHandler; +class NpadIrNfcHandler; +class UniquePads; +class NpadPalmaHandler; +class FirmwareResource; +class NpadVibration; +class NpadHighestBattery; +class NpadGcVibration; + +class CaptureButtonResource; +class HomeButtonResource; +class VibrationHandler; + +struct HandheldConfig; + +/// Handles Npad request from HID interfaces +class AbstractPad final { +public: + explicit AbstractPad(); + ~AbstractPad(); + + void SetExternals(AppletResourceHolder* applet_resource, + CaptureButtonResource* capture_button_resource, + HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource, + PalmaResource* palma_resource, VibrationHandler* vibration); + void SetNpadId(Core::HID::NpadIdType npad_id); + + Result Activate(); + Result Deactivate(); + + Result ActivateNpad(u64 aruid); + + NpadAbstractedPadHolder* GetAbstractedPadHolder(); + NpadAbstractPropertiesHandler* GetAbstractPropertiesHandler(); + NpadAbstractLedHandler* GetAbstractLedHandler(); + NpadAbstractIrSensorHandler* GetAbstractIrSensorHandler(); + NpadAbstractMcuHandler* GetAbstractMcuHandler(); + NpadAbstractNfcHandler* GetAbstractNfcHandler(); + NpadAbstractVibrationHandler* GetAbstractVibrationHandler(); + NpadAbstractSixAxisHandler* GetAbstractSixAxisHandler(); + NpadAbstractButtonHandler* GetAbstractButtonHandler(); + NpadAbstractBatteryHandler* GetAbstractBatteryHandler(); + + NpadN64VibrationDevice* GetN64VibrationDevice(); + NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index); + void GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list); + NpadGcVibrationDevice* GetGCVibrationDevice(); + + Core::HID::NpadIdType GetLastActiveNpad(); + void UpdateInterfaceType(); + void Update(); + + void UpdatePadState(); + void EnableAppletToGetInput(u64 aruid); + +private: + AppletResourceHolder* applet_resource_holder{nullptr}; + NpadAbstractedPadHolder abstract_pad_holder{}; + NpadAbstractPropertiesHandler properties_handler{}; + NpadAbstractLedHandler led_handler{}; + NpadAbstractIrSensorHandler ir_sensor_handler{}; + NpadAbstractNfcHandler nfc_handler{}; + NpadAbstractMcuHandler mcu_handler{}; + NpadAbstractVibrationHandler vibration_handler{}; + NpadAbstractSixAxisHandler sixaxis_handler{}; + NpadAbstractButtonHandler button_handler{}; + NpadAbstractBatteryHandler battery_handler{}; + NpadAbstractPalmaHandler palma_handler{}; + + NpadN64VibrationDevice vibration_n64{}; + NpadVibrationDevice vibration_left{}; + NpadVibrationDevice vibration_right{}; + NpadGcVibrationDevice vibration_gc{}; + + // SixAxisConfigHolder fullkey_config; + // SixAxisConfigHolder handheld_config; + // SixAxisConfigHolder dual_left_config; + // SixAxisConfigHolder dual_right_config; + // SixAxisConfigHolder left_config; + // SixAxisConfigHolder right_config; + + s32 ref_counter{}; + Core::HID::NpadInterfaceType interface_type{Core::HID::NpadInterfaceType::None}; +}; + +using FullAbstractPad = std::array<AbstractPad, MaxSupportedNpadIdTypes>; + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp new file mode 100644 index 000000000..8334dc34f --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/npad/npad_types.h" + +namespace Service::HID { + +Result NpadAbstractedPadHolder::RegisterAbstractPad(IAbstractedPad* abstracted_pad) { + if (list_size >= assignment_list.size()) { + return ResultNpadIsNotProController; + } + + for (std::size_t i = 0; i < list_size; i++) { + if (assignment_list[i].device_type == abstracted_pad->device_type) { + return ResultNpadIsNotProController; + } + } + + assignment_list[list_size] = { + .abstracted_pad = abstracted_pad, + .device_type = abstracted_pad->device_type, + .interface_type = abstracted_pad->interface_type, + .controller_id = abstracted_pad->controller_id, + }; + + list_size++; + return ResultSuccess; +} + +void NpadAbstractedPadHolder::RemoveAbstractPadByControllerId(u64 controller_id) { + if (list_size == 0) { + return; + } + if (controller_id == 0) { + return; + } + for (std::size_t i = 0; i < list_size; i++) { + if (assignment_list[i].controller_id != controller_id) { + continue; + } + for (std::size_t e = i + 1; e < list_size; e++) { + assignment_list[e - 1] = assignment_list[e]; + } + list_size--; + return; + } +} + +void NpadAbstractedPadHolder::DetachAbstractedPad() { + while (list_size > 0) { + for (std::size_t i = 1; i < list_size; i++) { + assignment_list[i - 1] = assignment_list[i]; + } + list_size--; + } +} + +u64 NpadAbstractedPadHolder::RemoveAbstractPadByAssignmentStyle( + Service::HID::AssignmentStyle assignment_style) { + for (std::size_t i = 0; i < list_size; i++) { + if ((assignment_style.raw & assignment_list[i].abstracted_pad->assignment_style.raw) == 0) { + continue; + } + for (std::size_t e = i + 1; e < list_size; e++) { + assignment_list[e - 1] = assignment_list[e]; + } + list_size--; + return list_size; + } + return list_size; +} + +u32 NpadAbstractedPadHolder::GetAbstractedPads(std::span<IAbstractedPad*> list) const { + u32 num_elements = std::min(static_cast<u32>(list.size()), list_size); + for (std::size_t i = 0; i < num_elements; i++) { + list[i] = assignment_list[i].abstracted_pad; + } + return num_elements; +} + +void NpadAbstractedPadHolder::SetAssignmentMode(const NpadJoyAssignmentMode& mode) { + assignment_mode = mode; +} + +NpadJoyAssignmentMode NpadAbstractedPadHolder::GetAssignmentMode() const { + return assignment_mode; +} + +std::size_t NpadAbstractedPadHolder::GetStyleIndexList( + std::span<Core::HID::NpadStyleIndex> list) const { + for (std::size_t i = 0; i < list_size; i++) { + list[i] = assignment_list[i].device_type; + } + return list_size; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h new file mode 100644 index 000000000..fb7f472e8 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> +#include <mutex> +#include <span> + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/npad/npad_types.h" + +namespace Service::HID { +struct IAbstractedPad; + +struct AbstractAssignmentHolder { + IAbstractedPad* abstracted_pad; + Core::HID::NpadStyleIndex device_type; + Core::HID::NpadInterfaceType interface_type; + INSERT_PADDING_BYTES(0x6); + u64 controller_id; +}; +static_assert(sizeof(AbstractAssignmentHolder) == 0x18, + "AbstractAssignmentHolder is an invalid size"); + +/// This is nn::hid::server::NpadAbstractedPadHolder +class NpadAbstractedPadHolder final { +public: + Result RegisterAbstractPad(IAbstractedPad* abstracted_pad); + void RemoveAbstractPadByControllerId(u64 controller_id); + void DetachAbstractedPad(); + u64 RemoveAbstractPadByAssignmentStyle(Service::HID::AssignmentStyle assignment_style); + u32 GetAbstractedPads(std::span<IAbstractedPad*> list) const; + + void SetAssignmentMode(const NpadJoyAssignmentMode& mode); + NpadJoyAssignmentMode GetAssignmentMode() const; + + std::size_t GetStyleIndexList(std::span<Core::HID::NpadStyleIndex> list) const; + +private: + std::array<AbstractAssignmentHolder, 5> assignment_list{}; + u32 list_size{}; + NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual}; +}; +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp new file mode 100644 index 000000000..04d276d61 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/abstracted_pad/abstract_palma_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" + +namespace Service::HID { + +NpadAbstractPalmaHandler::NpadAbstractPalmaHandler() {} + +NpadAbstractPalmaHandler::~NpadAbstractPalmaHandler() = default; + +void NpadAbstractPalmaHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractPalmaHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; + return; +} + +void NpadAbstractPalmaHandler::SetPalmaResource(PalmaResource* resource) { + palma_resource = resource; +} + +Result NpadAbstractPalmaHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractPalmaHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +void NpadAbstractPalmaHandler::UpdatePalmaState() { + // TODO +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h new file mode 100644 index 000000000..fbd2e67e5 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Service::HID { +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; +class PalmaResource; + +class NpadAbstractPalmaHandler final { +public: + explicit NpadAbstractPalmaHandler(); + ~NpadAbstractPalmaHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + void SetPalmaResource(PalmaResource* resource); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + void UpdatePalmaState(); + +private: + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + PalmaResource* palma_resource{nullptr}; + + s32 ref_counter{}; +}; + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp new file mode 100644 index 000000000..4897a2784 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp @@ -0,0 +1,322 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_util.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/npad/npad_resource.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/shared_memory_format.h" + +namespace Service::HID { + +NpadAbstractPropertiesHandler::NpadAbstractPropertiesHandler() {} + +NpadAbstractPropertiesHandler::~NpadAbstractPropertiesHandler() = default; + +void NpadAbstractPropertiesHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; + return; +} + +void NpadAbstractPropertiesHandler::SetAppletResource(AppletResourceHolder* applet_resource) { + applet_resource_holder = applet_resource; + return; +} + +void NpadAbstractPropertiesHandler::SetNpadId(Core::HID::NpadIdType npad_id) { + if (!IsNpadIdValid(npad_id)) { + ASSERT_MSG(false, "Invalid npad id"); + } + + npad_id_type = npad_id; +} + +Core::HID::NpadIdType NpadAbstractPropertiesHandler::GetNpadId() const { + return npad_id_type; +} + +Result NpadAbstractPropertiesHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + + if (ref_counter != 0) { + ref_counter++; + return ResultSuccess; + } + + const auto npad_index = NpadIdTypeToIndex(npad_id_type); + for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { + auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index); + auto& internal_state = + data->shared_memory_format->npad.npad_entry[npad_index].internal_state; + if (!data->flag.is_assigned) { + continue; + } + internal_state.fullkey_lifo.buffer_count = 0; + internal_state.handheld_lifo.buffer_count = 0; + internal_state.joy_dual_lifo.buffer_count = 0; + internal_state.joy_left_lifo.buffer_count = 0; + internal_state.joy_right_lifo.buffer_count = 0; + internal_state.palma_lifo.buffer_count = 0; + internal_state.system_ext_lifo.buffer_count = 0; + internal_state.gc_trigger_lifo.buffer_count = 0; + internal_state.sixaxis_fullkey_lifo.lifo.buffer_count = 0; + internal_state.sixaxis_handheld_lifo.lifo.buffer_count = 0; + internal_state.sixaxis_dual_left_lifo.lifo.buffer_count = 0; + internal_state.sixaxis_dual_right_lifo.lifo.buffer_count = 0; + internal_state.sixaxis_left_lifo.lifo.buffer_count = 0; + internal_state.sixaxis_right_lifo.lifo.buffer_count = 0; + + internal_state.style_tag = {Core::HID::NpadStyleSet::None}; + internal_state.assignment_mode = NpadJoyAssignmentMode::Dual; + internal_state.joycon_color = {}; + internal_state.fullkey_color = {}; + + internal_state.system_properties.raw = 0; + internal_state.button_properties.raw = 0; + internal_state.device_type.raw = 0; + + internal_state.battery_level_dual = Core::HID::NpadBatteryLevel::Empty; + internal_state.battery_level_left = Core::HID::NpadBatteryLevel::Empty; + internal_state.battery_level_right = Core::HID::NpadBatteryLevel::Empty; + + internal_state.applet_footer_type = AppletFooterUiType::None; + internal_state.applet_footer_attributes = {}; + internal_state.lark_type_l_and_main = {}; + internal_state.lark_type_r = {}; + + internal_state.sixaxis_fullkey_properties.is_newly_assigned.Assign(true); + internal_state.sixaxis_handheld_properties.is_newly_assigned.Assign(true); + internal_state.sixaxis_dual_left_properties.is_newly_assigned.Assign(true); + internal_state.sixaxis_dual_right_properties.is_newly_assigned.Assign(true); + internal_state.sixaxis_left_properties.is_newly_assigned.Assign(true); + internal_state.sixaxis_right_properties.is_newly_assigned.Assign(true); + } + + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractPropertiesHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +Result NpadAbstractPropertiesHandler::ActivateNpadUnknown0x88(u64 aruid) { + const auto npad_index = NpadIdTypeToIndex(npad_id_type); + for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { + auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index); + if (!data->flag.is_assigned || data->aruid != aruid) { + continue; + } + UpdateDeviceProperties(aruid, data->shared_memory_format->npad.npad_entry[npad_index]); + return ResultSuccess; + } + return ResultSuccess; +} + +void NpadAbstractPropertiesHandler::UpdateDeviceType() { + // TODO +} + +void NpadAbstractPropertiesHandler::UpdateDeviceColor() { + // TODO +} + +void NpadAbstractPropertiesHandler::UpdateFooterAttributes() { + // TODO +} + +void NpadAbstractPropertiesHandler::UpdateAllDeviceProperties() { + const auto npad_index = NpadIdTypeToIndex(npad_id_type); + for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { + auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index); + if (!data->flag.is_assigned) { + continue; + } + auto& npad_entry = data->shared_memory_format->npad.npad_entry[npad_index]; + UpdateDeviceProperties(data->aruid, npad_entry); + } +} + +Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetFullkeyInterfaceType() { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + if (abstract_pad->device_type != Core::HID::NpadStyleIndex::Fullkey) { + continue; + } + if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) { + // Abort + continue; + } + return abstract_pad->interface_type; + } + + return Core::HID::NpadInterfaceType::None; +} + +Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetInterfaceType() { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + if (!abstract_pad->disabled_feature_set.has_identification_code) { + continue; + } + if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) { + // Abort + continue; + } + return abstract_pad->interface_type; + } + return Core::HID::NpadInterfaceType::None; +} + +Core::HID::NpadStyleSet NpadAbstractPropertiesHandler::GetStyleSet(u64 aruid) { + // TODO + return Core::HID::NpadStyleSet::None; +} + +std::size_t NpadAbstractPropertiesHandler::GetAbstractedPadsWithStyleTag( + std::span<IAbstractedPad*> list, Core::HID::NpadStyleTag style) { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + if (count == 0) { + return count; + } + + bool is_supported_style_set{}; + const auto result = applet_resource_holder->shared_npad_resource->IsSupportedNpadStyleSet( + is_supported_style_set, applet_resource_holder->applet_resource->GetActiveAruid()); + + if (!is_supported_style_set || result.IsError()) { + for (std::size_t i = 0; i < count; i++) { + // TODO + } + return count; + } + + std::size_t filtered_count{}; + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + const bool is_enabled = true; + if (is_enabled) { + list[filtered_count] = abstract_pad; + filtered_count++; + } + } + + return filtered_count; +} + +std::size_t NpadAbstractPropertiesHandler::GetAbstractedPads(std::span<IAbstractedPad*> list) { + Core::HID::NpadStyleTag style{ + GetStyleSet(applet_resource_holder->applet_resource->GetActiveAruid())}; + return GetAbstractedPadsWithStyleTag(list, style); +} + +AppletFooterUiType NpadAbstractPropertiesHandler::GetAppletFooterUiType() { + return applet_ui_type.footer; +} + +AppletDetailedUiType NpadAbstractPropertiesHandler::GetAppletDetailedUiType() { + return applet_ui_type; +} + +void NpadAbstractPropertiesHandler::UpdateDeviceProperties(u64 aruid, + NpadSharedMemoryEntry& internal_state) { + // TODO +} + +Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetNpadInterfaceType() { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) { + // Abort + continue; + } + return abstract_pad->interface_type; + } + + return Core::HID::NpadInterfaceType::None; +} + +Result NpadAbstractPropertiesHandler::GetNpadFullKeyGripColor( + Core::HID::NpadColor& main_color, Core::HID::NpadColor& sub_color) const { + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + if (applet_ui_type.footer != AppletFooterUiType::SwitchProController) { + return ResultNpadIsNotProController; + } + + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + return ResultSuccess; + } + + return ResultNpadIsNotProController; +} + +void NpadAbstractPropertiesHandler::GetNpadLeftRightInterfaceType( + Core::HID::NpadInterfaceType& out_left_interface, + Core::HID::NpadInterfaceType& out_right_interface) const { + out_left_interface = Core::HID::NpadInterfaceType::None; + out_right_interface = Core::HID::NpadInterfaceType::None; + + std::array<IAbstractedPad*, 5> abstract_pads{}; + const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads); + + for (std::size_t i = 0; i < count; i++) { + auto* abstract_pad = abstract_pads[i]; + if (!abstract_pad->internal_flags.is_connected) { + continue; + } + if (abstract_pad->assignment_style.is_external_left_assigned && + abstract_pad->assignment_style.is_handheld_left_assigned) { + if (abstract_pad->interface_type > Core::HID::NpadInterfaceType::Embedded) { + // Abort + continue; + } + out_left_interface = abstract_pad->interface_type; + continue; + } + if (abstract_pad->assignment_style.is_external_right_assigned && + abstract_pad->assignment_style.is_handheld_right_assigned) { + if (abstract_pad->interface_type > Core::HID::NpadInterfaceType::Embedded) { + // Abort + continue; + } + out_right_interface = abstract_pad->interface_type; + continue; + } + } +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h new file mode 100644 index 000000000..fa6827899 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h @@ -0,0 +1,86 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <span> + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/npad/npad_types.h" + +namespace Service::HID { +struct NpadSharedMemoryEntry; + +struct AppletResourceHolder; +class NpadAbstractedPadHolder; + +struct ColorProperties { + ColorAttribute attribute; + Core::HID::NpadControllerColor color; + INSERT_PADDING_BYTES(0x4); +}; + +/// Handles Npad request from HID interfaces +class NpadAbstractPropertiesHandler final { +public: + explicit NpadAbstractPropertiesHandler(); + ~NpadAbstractPropertiesHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetAppletResource(AppletResourceHolder* applet_resource); + void SetNpadId(Core::HID::NpadIdType npad_id); + + Core::HID::NpadIdType GetNpadId() const; + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + Result ActivateNpadUnknown0x88(u64 aruid); + + void UpdateDeviceType(); + void UpdateDeviceColor(); + void UpdateFooterAttributes(); + void UpdateAllDeviceProperties(); + + Core::HID::NpadInterfaceType GetFullkeyInterfaceType(); + Core::HID::NpadInterfaceType GetInterfaceType(); + + Core::HID::NpadStyleSet GetStyleSet(u64 aruid); + std::size_t GetAbstractedPadsWithStyleTag(std::span<IAbstractedPad*> list, + Core::HID::NpadStyleTag style); + std::size_t GetAbstractedPads(std::span<IAbstractedPad*> list); + + AppletFooterUiType GetAppletFooterUiType(); + + AppletDetailedUiType GetAppletDetailedUiType(); + + void UpdateDeviceProperties(u64 aruid, NpadSharedMemoryEntry& internal_state); + + Core::HID::NpadInterfaceType GetNpadInterfaceType(); + + Result GetNpadFullKeyGripColor(Core::HID::NpadColor& main_color, + Core::HID::NpadColor& sub_color) const; + + void GetNpadLeftRightInterfaceType(Core::HID::NpadInterfaceType& param_2, + Core::HID::NpadInterfaceType& param_3) const; + +private: + AppletResourceHolder* applet_resource_holder{nullptr}; + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + Core::HID::NpadIdType npad_id_type{Core::HID::NpadIdType::Invalid}; + s32 ref_counter{}; + Core::HID::DeviceIndex device_type{}; + AppletDetailedUiType applet_ui_type{}; + AppletFooterUiAttributes applet_ui_attributes{}; + bool is_vertical{}; + bool is_horizontal{}; + bool use_plus{}; + bool use_minus{}; + bool has_directional_buttons{}; + ColorProperties fullkey_color{}; + ColorProperties left_color{}; + ColorProperties right_color{}; +}; +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp new file mode 100644 index 000000000..6d759298e --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp @@ -0,0 +1,154 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/hid_util.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/shared_memory_format.h" + +namespace Service::HID { + +NpadAbstractSixAxisHandler::NpadAbstractSixAxisHandler() {} + +NpadAbstractSixAxisHandler::~NpadAbstractSixAxisHandler() = default; + +void NpadAbstractSixAxisHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractSixAxisHandler::SetAppletResource(AppletResourceHolder* applet_resource) { + applet_resource_holder = applet_resource; +} + +void NpadAbstractSixAxisHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; +} + +void NpadAbstractSixAxisHandler::SetSixaxisResource(SixAxisResource* resource) { + six_axis_resource = resource; +} + +Result NpadAbstractSixAxisHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractSixAxisHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +u64 NpadAbstractSixAxisHandler::IsFirmwareUpdateAvailable() { + // TODO + return false; +} + +Result NpadAbstractSixAxisHandler::UpdateSixAxisState() { + Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); + for (std::size_t i = 0; i < AruidIndexMax; i++) { + auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i); + if (data->flag.is_assigned) { + continue; + } + auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; + UpdateSixaxisInternalState(npad_entry, data->aruid, + data->flag.enable_six_axis_sensor.As<bool>()); + } + return ResultSuccess; +} + +Result NpadAbstractSixAxisHandler::UpdateSixAxisState(u64 aruid) { + Core::HID::NpadIdType npad_id = properties_handler->GetNpadId(); + auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid); + if (data == nullptr) { + return ResultSuccess; + } + auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)]; + UpdateSixaxisInternalState(npad_entry, data->aruid, + data->flag.enable_six_axis_sensor.As<bool>()); + return ResultSuccess; +} + +Result NpadAbstractSixAxisHandler::UpdateSixAxisState2(u64 aruid) { + const auto npad_index = NpadIdTypeToIndex(properties_handler->GetNpadId()); + AruidData* aruid_data = applet_resource_holder->applet_resource->GetAruidData(aruid); + if (aruid_data == nullptr) { + return ResultSuccess; + } + auto& npad_internal_state = aruid_data->shared_memory_format->npad.npad_entry[npad_index]; + UpdateSixaxisInternalState(npad_internal_state, aruid, + aruid_data->flag.enable_six_axis_sensor.As<bool>()); + return ResultSuccess; +} + +void NpadAbstractSixAxisHandler::UpdateSixaxisInternalState(NpadSharedMemoryEntry& npad_entry, + u64 aruid, bool is_sensor_enabled) { + const Core::HID::NpadStyleTag style_tag{properties_handler->GetStyleSet(aruid)}; + + if (!style_tag.palma) { + UpdateSixaxisFullkeyLifo(style_tag, npad_entry.internal_state.sixaxis_fullkey_lifo, + is_sensor_enabled); + } else { + UpdateSixAxisPalmaLifo(style_tag, npad_entry.internal_state.sixaxis_fullkey_lifo, + is_sensor_enabled); + } + UpdateSixaxisHandheldLifo(style_tag, npad_entry.internal_state.sixaxis_handheld_lifo, + is_sensor_enabled); + UpdateSixaxisDualLifo(style_tag, npad_entry.internal_state.sixaxis_dual_left_lifo, + is_sensor_enabled); + UpdateSixaxisDualLifo(style_tag, npad_entry.internal_state.sixaxis_dual_right_lifo, + is_sensor_enabled); + UpdateSixaxisLeftLifo(style_tag, npad_entry.internal_state.sixaxis_left_lifo, + is_sensor_enabled); + UpdateSixaxisRightLifo(style_tag, npad_entry.internal_state.sixaxis_right_lifo, + is_sensor_enabled); + // TODO: Set sixaxis properties +} + +void NpadAbstractSixAxisHandler::UpdateSixaxisFullkeyLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, + bool is_sensor_enabled) { + // TODO +} + +void NpadAbstractSixAxisHandler::UpdateSixAxisPalmaLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, + bool is_sensor_enabled) { + // TODO +} + +void NpadAbstractSixAxisHandler::UpdateSixaxisHandheldLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, + bool is_sensor_enabled) { + // TODO +} + +void NpadAbstractSixAxisHandler::UpdateSixaxisDualLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, + bool is_sensor_enabled) { + // TODO +} + +void NpadAbstractSixAxisHandler::UpdateSixaxisLeftLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, + bool is_sensor_enabled) { + // TODO +} + +void NpadAbstractSixAxisHandler::UpdateSixaxisRightLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, + bool is_sensor_enabled) { + // TODO +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h new file mode 100644 index 000000000..9c20459e9 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h @@ -0,0 +1,61 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Service::HID { +class SixAxisResource; +struct AppletResourceHolder; +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; +struct NpadSixAxisSensorLifo; + +/// Handles Npad request from HID interfaces +class NpadAbstractSixAxisHandler final { +public: + explicit NpadAbstractSixAxisHandler(); + ~NpadAbstractSixAxisHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetAppletResource(AppletResourceHolder* applet_resource); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + void SetSixaxisResource(SixAxisResource* resource); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + u64 IsFirmwareUpdateAvailable(); + + Result UpdateSixAxisState(); + Result UpdateSixAxisState(u64 aruid); + Result UpdateSixAxisState2(u64 aruid); + +private: + void UpdateSixaxisInternalState(NpadSharedMemoryEntry& npad_entry, u64 aruid, + bool is_sensor_enabled); + void UpdateSixaxisFullkeyLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); + void UpdateSixAxisPalmaLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); + void UpdateSixaxisHandheldLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); + void UpdateSixaxisDualLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); + void UpdateSixaxisLeftLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); + void UpdateSixaxisRightLifo(Core::HID::NpadStyleTag style_tag, + NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled); + + AppletResourceHolder* applet_resource_holder{nullptr}; + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + SixAxisResource* six_axis_resource{nullptr}; + + s32 ref_counter{}; +}; + +} // namespace Service::HID diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp new file mode 100644 index 000000000..a00d6c9de --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/hid_util.h" +#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h" +#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h" +#include "hid_core/resources/abstracted_pad/abstract_vibration_handler.h" +#include "hid_core/resources/applet_resource.h" +#include "hid_core/resources/npad/npad_vibration.h" +#include "hid_core/resources/vibration/gc_vibration_device.h" +#include "hid_core/resources/vibration/n64_vibration_device.h" +#include "hid_core/resources/vibration/vibration_device.h" + +namespace Service::HID { + +NpadAbstractVibrationHandler::NpadAbstractVibrationHandler() {} + +NpadAbstractVibrationHandler::~NpadAbstractVibrationHandler() = default; + +void NpadAbstractVibrationHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) { + abstract_pad_holder = holder; +} + +void NpadAbstractVibrationHandler::SetAppletResource(AppletResourceHolder* applet_resource) { + applet_resource_holder = applet_resource; +} + +void NpadAbstractVibrationHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) { + properties_handler = handler; +} + +void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) { + n64_vibration_device = n64_device; +} + +void NpadAbstractVibrationHandler::SetVibration(std::span<NpadVibrationDevice*> device) { + for (std::size_t i = 0; i < device.size() && i < vibration_device.size(); i++) { + vibration_device[i] = device[i]; + } +} + +void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) { + gc_vibration_device = gc_device; +} + +Result NpadAbstractVibrationHandler::IncrementRefCounter() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultNpadHandlerOverflow; + } + ref_counter++; + return ResultSuccess; +} + +Result NpadAbstractVibrationHandler::DecrementRefCounter() { + if (ref_counter == 0) { + return ResultNpadHandlerNotInitialized; + } + ref_counter--; + return ResultSuccess; +} + +void NpadAbstractVibrationHandler::UpdateVibrationState() { + const bool is_handheld_hid_enabled = + applet_resource_holder->handheld_config->is_handheld_hid_enabled; + const bool is_force_handheld_style_vibration = + applet_resource_holder->handheld_config->is_force_handheld_style_vibration; + + if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) { + // TODO + } +} +} // 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 new file mode 100644 index 000000000..aeb07ce86 --- /dev/null +++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <span> + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" + +namespace Service::HID { +struct AppletResourceHolder; +class NpadAbstractedPadHolder; +class NpadAbstractPropertiesHandler; +class NpadGcVibrationDevice; +class NpadVibrationDevice; +class NpadN64VibrationDevice; +class NpadVibration; + +/// Keeps track of battery levels and updates npad battery shared memory values +class NpadAbstractVibrationHandler final { +public: + explicit NpadAbstractVibrationHandler(); + ~NpadAbstractVibrationHandler(); + + void SetAbstractPadHolder(NpadAbstractedPadHolder* holder); + void SetAppletResource(AppletResourceHolder* applet_resource); + void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler); + + void SetN64Vibration(NpadN64VibrationDevice* n64_device); + void SetVibration(std::span<NpadVibrationDevice*> device); + void SetGcVibration(NpadGcVibrationDevice* gc_device); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + void UpdateVibrationState(); + +private: + AppletResourceHolder* applet_resource_holder{nullptr}; + NpadAbstractedPadHolder* abstract_pad_holder{nullptr}; + NpadAbstractPropertiesHandler* properties_handler{nullptr}; + + NpadN64VibrationDevice* n64_vibration_device{nullptr}; + std::array<NpadVibrationDevice*, 2> vibration_device{}; + NpadGcVibrationDevice* gc_vibration_device{nullptr}; + NpadVibration* vibration_handler{nullptr}; + s32 ref_counter{}; +}; +} // namespace Service::HID diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index 1f8a0f8ab..97537a2e2 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -193,7 +193,7 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) { case Core::HID::NpadStyleIndex::None: ASSERT(false); break; - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: shared_memory->fullkey_color.attribute = ColorAttribute::Ok; shared_memory->fullkey_color.fullkey = body_colors.fullkey; shared_memory->battery_level_dual = battery_level.dual.battery_level; @@ -491,7 +491,7 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { case Core::HID::NpadStyleIndex::None: ASSERT(false); break; - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::NES: case Core::HID::NpadStyleIndex::SNES: case Core::HID::NpadStyleIndex::N64: @@ -1292,7 +1292,7 @@ Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) { auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::Pokeball: return controller.shared_memory->sixaxis_fullkey_properties; case Core::HID::NpadStyleIndex::Handheld: @@ -1315,7 +1315,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::Pokeball: return controller.shared_memory->sixaxis_fullkey_properties; case Core::HID::NpadStyleIndex::Handheld: diff --git a/src/hid_core/resources/npad/npad_data.cpp b/src/hid_core/resources/npad/npad_data.cpp index c7e9760cb..29ad5cb08 100644 --- a/src/hid_core/resources/npad/npad_data.cpp +++ b/src/hid_core/resources/npad/npad_data.cpp @@ -151,7 +151,7 @@ Core::HID::NpadStyleSet NPadData::GetSupportedNpadStyleSet() const { bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const { Core::HID::NpadStyleTag style = {supported_npad_style_set}; switch (style_index) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: return style.fullkey.As<bool>(); case Core::HID::NpadStyleIndex::Handheld: return style.handheld.As<bool>(); diff --git a/src/hid_core/resources/npad/npad_types.h b/src/hid_core/resources/npad/npad_types.h index a02f9cf16..074dd40cf 100644 --- a/src/hid_core/resources/npad/npad_types.h +++ b/src/hid_core/resources/npad/npad_types.h @@ -252,4 +252,103 @@ enum class NpadLagerType : u32 { U, }; +// nn::hidtypes::FeatureType +struct FeatureType { + union { + u64 raw{}; + BitField<0, 1, u64> has_left_analog_stick; + BitField<1, 1, u64> has_right_analog_stick; + BitField<2, 1, u64> has_left_joy_six_axis_sensor; + BitField<3, 1, u64> has_right_joy_six_axis_sensor; + BitField<4, 1, u64> has_fullkey_joy_six_axis_sensor; + BitField<5, 1, u64> has_left_lra_vibration_device; + BitField<6, 1, u64> has_right_lra_vibration_device; + BitField<7, 1, u64> has_gc_vibration_device; + BitField<8, 1, u64> has_erm_vibration_device; + BitField<9, 1, u64> has_left_joy_rail_bus; + BitField<10, 1, u64> has_right_joy_rail_bus; + BitField<11, 1, u64> has_internal_bus; + BitField<12, 1, u64> is_palma; + BitField<13, 1, u64> has_nfc; + BitField<14, 1, u64> has_ir_sensor; + BitField<15, 1, u64> is_analog_stick_calibration_supported; + BitField<16, 1, u64> is_six_axis_Sensor_user_calibration_supported; + BitField<17, 1, u64> has_left_right_joy_battery; + BitField<18, 1, u64> has_fullkey_battery; + BitField<19, 1, u64> is_disconnect_controller_if_battery_none; + BitField<20, 1, u64> has_controller_color; + BitField<21, 1, u64> has_grip_color; + BitField<22, 1, u64> has_identification_code; + BitField<23, 1, u64> has_bluetooth_address; + BitField<24, 1, u64> has_mcu; + BitField<25, 1, u64> has_notification_led; + BitField<26, 1, u64> has_directional_buttons; + BitField<27, 1, u64> has_indicator_led; + BitField<28, 1, u64> is_button_config_embedded_supported; + BitField<29, 1, u64> is_button_config_full_supported; + BitField<30, 1, u64> is_button_config_left_supported; + BitField<31, 1, u64> is_button_config_right_supported; + BitField<32, 1, u64> is_usb_hid_device; + BitField<33, 1, u64> is_kuina_device; + BitField<34, 1, u64> is_direct_usb_to_bt_switching_device; + BitField<35, 1, u64> is_normalize_analog_stick_with_inner_cross; + }; +}; +static_assert(sizeof(FeatureType) == 8, "FeatureType is an invalid size"); + +// This is nn::hid::AssignmentStyle +struct AssignmentStyle { + union { + u32 raw{}; + BitField<0, 1, u32> is_external_assigned; + BitField<1, 1, u32> is_external_left_assigned; + BitField<2, 1, u32> is_external_right_assigned; + BitField<3, 1, u32> is_handheld_assigned; + BitField<4, 1, u32> is_handheld_left_assigned; + BitField<5, 1, u32> is_handheld_right_assigned; + }; +}; +static_assert(sizeof(AssignmentStyle) == 4, "AssignmentStyle is an invalid size"); + +// This is nn::hid::server::IAbstractedPad::InternalFlags +struct InternalFlags { + union { + u32 raw{}; + BitField<0, 1, u32> is_bound; + BitField<1, 1, u32> is_connected; + BitField<2, 1, u32> is_battery_low_ovln_required; + BitField<3, 1, u32> is_battery_low_ovln_delay_required; + BitField<4, 1, u32> is_sample_recieved; + BitField<5, 1, u32> is_virtual_input; + BitField<6, 1, u32> is_wired; + BitField<8, 1, u32> use_center_clamp; + BitField<9, 1, u32> has_virtual_six_axis_sensor_acceleration; + BitField<10, 1, u32> has_virtual_six_axis_sensor_angle; + BitField<11, 1, u32> is_debug_pad; + }; +}; +static_assert(sizeof(InternalFlags) == 4, "InternalFlags is an invalid size"); + +/// This is nn::hid::server::IAbstractedPad +struct IAbstractedPad { + InternalFlags internal_flags; + u64 controller_id; + u32 controller_number; + u64 low_battery_display_delay_time; + u64 low_battery_display_delay_interval; + FeatureType feature_set; + FeatureType disabled_feature_set; + AssignmentStyle assignment_style; + Core::HID::NpadStyleIndex device_type; + Core::HID::NpadInterfaceType interface_type; + Core::HID::NpadPowerInfo power_info; + u32 pad_state; + u32 button_mask; + u32 system_button_mask; + u8 indicator; + std::vector<f32> virtual_six_axis_sensor_acceleration; + std::vector<f32> virtual_six_axis_sensor_angle; + u64 xcd_handle; + u64 color; +}; } // namespace Service::HID diff --git a/src/hid_core/resources/npad/npad_vibration.cpp b/src/hid_core/resources/npad/npad_vibration.cpp new file mode 100644 index 000000000..3bdd55dec --- /dev/null +++ b/src/hid_core/resources/npad/npad_vibration.cpp @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/npad/npad_vibration.h" + +namespace Service::HID { + +NpadVibration::NpadVibration() {} + +NpadVibration::~NpadVibration() = default; + +Result NpadVibration::Activate() { + std::scoped_lock lock{mutex}; + + const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume(); + // if (master_volume < 0.0f || master_volume > 1.0f) { + // return ResultVibrationStrenghtOutOfRange; + // } + + volume = master_volume; + return ResultSuccess; +} + +Result NpadVibration::Deactivate() { + return ResultSuccess; +} + +Result NpadVibration::SetVibrationMasterVolume(f32 master_volume) { + std::scoped_lock lock{mutex}; + + if (master_volume < 0.0f && master_volume > 1.0f) { + return ResultVibrationStrenghtOutOfRange; + } + + volume = master_volume; + // nn::settings::system::SetVibrationMasterVolume(master_volume); + + return ResultSuccess; +} + +Result NpadVibration::GetVibrationVolume(f32& out_volume) const { + std::scoped_lock lock{mutex}; + out_volume = volume; + return ResultSuccess; +} + +Result NpadVibration::GetVibrationMasterVolume(f32& out_volume) const { + std::scoped_lock lock{mutex}; + + const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume(); + // if (master_volume < 0.0f || master_volume > 1.0f) { + // return ResultVibrationStrenghtOutOfRange; + // } + + out_volume = master_volume; + return ResultSuccess; +} + +Result NpadVibration::BeginPermitVibrationSession(u64 aruid) { + std::scoped_lock lock{mutex}; + session_aruid = aruid; + volume = 1.0; + return ResultSuccess; +} + +Result NpadVibration::EndPermitVibrationSession() { + std::scoped_lock lock{mutex}; + + const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume(); + // if (master_volume < 0.0f || master_volume > 1.0f) { + // return ResultVibrationStrenghtOutOfRange; + // } + + volume = master_volume; + session_aruid = 0; + return ResultSuccess; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/npad/npad_vibration.h b/src/hid_core/resources/npad/npad_vibration.h new file mode 100644 index 000000000..0748aeffc --- /dev/null +++ b/src/hid_core/resources/npad/npad_vibration.h @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <mutex> + +#include "common/common_types.h" +#include "core/hle/result.h" + +namespace Service::HID { + +class NpadVibration final { +public: + explicit NpadVibration(); + ~NpadVibration(); + + Result Activate(); + Result Deactivate(); + + Result SetVibrationMasterVolume(f32 master_volume); + Result GetVibrationVolume(f32& out_volume) const; + Result GetVibrationMasterVolume(f32& out_volume) const; + + Result BeginPermitVibrationSession(u64 aruid); + Result EndPermitVibrationSession(); + +private: + f32 volume{}; + u64 session_aruid{}; + mutable std::mutex mutex; +}; + +} // namespace Service::HID diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp index 8a9677c50..da12d2d5a 100644 --- a/src/hid_core/resources/six_axis/six_axis.cpp +++ b/src/hid_core/resources/six_axis/six_axis.cpp @@ -114,7 +114,7 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { case Core::HID::NpadStyleIndex::None: ASSERT(false); break; - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: set_motion_state(sixaxis_fullkey_state, motion_state[0]); break; case Core::HID::NpadStyleIndex::Handheld: @@ -345,7 +345,7 @@ SixAxis::SixaxisParameters& SixAxis::GetSixaxisState( const Core::HID::SixAxisSensorHandle& sixaxis_handle) { auto& controller = GetControllerFromHandle(sixaxis_handle); switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::Pokeball: return controller.sixaxis_fullkey; case Core::HID::NpadStyleIndex::Handheld: @@ -368,7 +368,7 @@ const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState( const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { const auto& controller = GetControllerFromHandle(sixaxis_handle); switch (sixaxis_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::Pokeball: return controller.sixaxis_fullkey; case Core::HID::NpadStyleIndex::Handheld: diff --git a/src/hid_core/resources/vibration/gc_vibration_device.cpp b/src/hid_core/resources/vibration/gc_vibration_device.cpp new file mode 100644 index 000000000..f01f81b9a --- /dev/null +++ b/src/hid_core/resources/vibration/gc_vibration_device.cpp @@ -0,0 +1,106 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/npad/npad_vibration.h" +#include "hid_core/resources/vibration/gc_vibration_device.h" + +namespace Service::HID { + +NpadGcVibrationDevice::NpadGcVibrationDevice() {} + +Result NpadGcVibrationDevice::IncrementRefCounter() { + if (ref_counter == 0 && is_mounted) { + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsSuccess()) { + // TODO: SendVibrationGcErmCommand + } + } + ref_counter++; + return ResultSuccess; +} + +Result NpadGcVibrationDevice::DecrementRefCounter() { + if (ref_counter == 1 && !is_mounted) { + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsSuccess()) { + // TODO: SendVibrationGcErmCommand + } + } + + if (ref_counter > 0) { + ref_counter--; + } + + return ResultSuccess; +} + +Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command) { + if (!is_mounted) { + return ResultSuccess; + } + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsError()) { + return result; + } + if (volume == 0.0) { + command = Core::HID::VibrationGcErmCommand::Stop; + } else { + if (command > Core::HID::VibrationGcErmCommand::StopHard) { + // Abort + return ResultSuccess; + } + } + // TODO: SendVibrationGcErmCommand + return ResultSuccess; +} + +Result NpadGcVibrationDevice::GetActualVibrationGcErmCommand( + Core::HID::VibrationGcErmCommand& out_command) { + if (!is_mounted) { + out_command = Core::HID::VibrationGcErmCommand::Stop; + return ResultSuccess; + } + + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsError()) { + return result; + } + if (volume == 0.0f) { + out_command = Core::HID::VibrationGcErmCommand::Stop; + return ResultSuccess; + } + + // TODO: GetActualVibrationGcErmCommand + return ResultSuccess; +} + +Result NpadGcVibrationDevice::SendVibrationNotificationPattern( + Core::HID::VibrationGcErmCommand command) { + if (!is_mounted) { + return ResultSuccess; + } + + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsError()) { + return result; + } + if (volume <= 0.0f) { + command = Core::HID::VibrationGcErmCommand::Stop; + } + if (command > Core::HID::VibrationGcErmCommand::StopHard) { + // Abort + return ResultSuccess; + } + + // TODO: SendVibrationNotificationPattern + return ResultSuccess; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/vibration/gc_vibration_device.h b/src/hid_core/resources/vibration/gc_vibration_device.h new file mode 100644 index 000000000..87abca57d --- /dev/null +++ b/src/hid_core/resources/vibration/gc_vibration_device.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> +#include <mutex> + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/vibration/vibration_base.h" + +namespace Service::HID { +class NpadVibration; + +/// Handles Npad request from HID interfaces +class NpadGcVibrationDevice final : public NpadVibrationBase { +public: + explicit NpadGcVibrationDevice(); + + Result IncrementRefCounter() override; + Result DecrementRefCounter() override; + + Result SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command); + + Result GetActualVibrationGcErmCommand(Core::HID::VibrationGcErmCommand& out_command); + Result SendVibrationNotificationPattern(Core::HID::VibrationGcErmCommand command); +}; +} // 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 new file mode 100644 index 000000000..639f87abf --- /dev/null +++ b/src/hid_core/resources/vibration/n64_vibration_device.cpp @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/npad/npad_vibration.h" +#include "hid_core/resources/vibration/n64_vibration_device.h" + +namespace Service::HID { + +NpadN64VibrationDevice::NpadN64VibrationDevice() {} + +Result NpadN64VibrationDevice::IncrementRefCounter() { + if (ref_counter == 0 && is_mounted) { + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsSuccess()) { + // TODO: SendVibrationInBool + } + } + + ref_counter++; + return ResultSuccess; +} + +Result NpadN64VibrationDevice::DecrementRefCounter() { + if (ref_counter == 1) { + if (!is_mounted) { + ref_counter = 0; + if (is_mounted != false) { + // TODO: SendVibrationInBool + } + return ResultSuccess; + } + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsSuccess()) { + // TODO + } + } + + if (ref_counter > 0) { + ref_counter--; + } + + return ResultSuccess; +} + +Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) { + if (ref_counter < 1) { + return ResultVibrationNotInitialized; + } + if (is_mounted) { + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsError()) { + return result; + } + // TODO: SendVibrationInBool + } + return ResultSuccess; +} + +Result NpadN64VibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u32 pattern) { + if (!is_mounted) { + return ResultSuccess; + } + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsError()) { + return result; + } + if (volume <= 0.0) { + pattern = 0; + } + // TODO: SendVibrationNotificationPattern + return ResultSuccess; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/vibration/n64_vibration_device.h b/src/hid_core/resources/vibration/n64_vibration_device.h new file mode 100644 index 000000000..54e6efc1a --- /dev/null +++ b/src/hid_core/resources/vibration/n64_vibration_device.h @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> +#include <mutex> + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/vibration/vibration_base.h" + +namespace Service::HID { +class NpadVibration; + +/// Handles Npad request from HID interfaces +class NpadN64VibrationDevice final : public NpadVibrationBase { +public: + explicit NpadN64VibrationDevice(); + + Result IncrementRefCounter() override; + Result DecrementRefCounter() override; + + Result SendValueInBool(bool is_vibrating); + Result SendVibrationNotificationPattern(u32 pattern); +}; +} // namespace Service::HID diff --git a/src/hid_core/resources/vibration/vibration_base.cpp b/src/hid_core/resources/vibration/vibration_base.cpp new file mode 100644 index 000000000..350f349c2 --- /dev/null +++ b/src/hid_core/resources/vibration/vibration_base.cpp @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/npad/npad_vibration.h" +#include "hid_core/resources/vibration/vibration_base.h" + +namespace Service::HID { + +NpadVibrationBase::NpadVibrationBase() {} + +Result NpadVibrationBase::IncrementRefCounter() { + ref_counter++; + return ResultSuccess; +} + +Result NpadVibrationBase::DecrementRefCounter() { + if (ref_counter > 0) { + ref_counter--; + } + + return ResultSuccess; +} + +bool NpadVibrationBase::IsVibrationMounted() const { + return is_mounted; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/vibration/vibration_base.h b/src/hid_core/resources/vibration/vibration_base.h new file mode 100644 index 000000000..c6c5fc4d9 --- /dev/null +++ b/src/hid_core/resources/vibration/vibration_base.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/result.h" + +namespace Service::HID { +class NpadVibration; + +/// Handles Npad request from HID interfaces +class NpadVibrationBase { +public: + explicit NpadVibrationBase(); + + virtual Result IncrementRefCounter(); + virtual Result DecrementRefCounter(); + + bool IsVibrationMounted() const; + +protected: + u64 xcd_handle{}; + s32 ref_counter{}; + bool is_mounted{}; + NpadVibration* vibration_handler{nullptr}; +}; +} // namespace Service::HID diff --git a/src/hid_core/resources/vibration/vibration_device.cpp b/src/hid_core/resources/vibration/vibration_device.cpp new file mode 100644 index 000000000..888c3a7ed --- /dev/null +++ b/src/hid_core/resources/vibration/vibration_device.cpp @@ -0,0 +1,84 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "hid_core/hid_result.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/npad/npad_vibration.h" +#include "hid_core/resources/vibration/vibration_device.h" + +namespace Service::HID { + +NpadVibrationDevice::NpadVibrationDevice() {} + +Result NpadVibrationDevice::IncrementRefCounter() { + ref_counter++; + return ResultSuccess; +} + +Result NpadVibrationDevice::DecrementRefCounter() { + if (ref_counter > 0) { + ref_counter--; + } + + return ResultSuccess; +} + +Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& value) { + if (ref_counter == 0) { + return ResultVibrationNotInitialized; + } + if (!is_mounted) { + return ResultSuccess; + } + + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsError()) { + return result; + } + if (volume <= 0.0f) { + // TODO: SendVibrationValue + return ResultSuccess; + } + + Core::HID::VibrationValue vibration_value = value; + vibration_value.high_amplitude *= volume; + vibration_value.low_amplitude *= volume; + + // TODO: SendVibrationValue + return ResultSuccess; +} + +Result NpadVibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u32 pattern) { + if (!is_mounted) { + return ResultSuccess; + } + + f32 volume = 1.0f; + const auto result = vibration_handler->GetVibrationVolume(volume); + if (result.IsError()) { + return result; + } + if (volume <= 0.0) { + pattern = 0; + } + + // return xcd_handle->SendVibrationNotificationPattern(pattern); + return ResultSuccess; +} + +Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) { + if (ref_counter < 1) { + return ResultVibrationNotInitialized; + } + + out_value = Core::HID::DEFAULT_VIBRATION_VALUE; + if (!is_mounted) { + return ResultSuccess; + } + + // TODO: SendVibrationValue + return ResultSuccess; +} + +} // namespace Service::HID diff --git a/src/hid_core/resources/vibration/vibration_device.h b/src/hid_core/resources/vibration/vibration_device.h new file mode 100644 index 000000000..3574ad60b --- /dev/null +++ b/src/hid_core/resources/vibration/vibration_device.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> +#include <mutex> + +#include "common/common_types.h" +#include "core/hle/result.h" +#include "hid_core/hid_types.h" +#include "hid_core/resources/npad/npad_types.h" +#include "hid_core/resources/vibration/vibration_base.h" + +namespace Service::HID { +class NpadVibration; + +/// Handles Npad request from HID interfaces +class NpadVibrationDevice final : public NpadVibrationBase { +public: + explicit NpadVibrationDevice(); + + Result IncrementRefCounter(); + Result DecrementRefCounter(); + + Result SendVibrationValue(const Core::HID::VibrationValue& value); + Result SendVibrationNotificationPattern(u32 pattern); + + Result GetActualVibrationValue(Core::HID::VibrationValue& out_value); + +private: + u32 device_index{}; +}; + +} // namespace Service::HID diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 8b340ee6c..48ce860ad 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -41,7 +41,7 @@ void UpdateController(Core::HID::EmulatedController* controller, bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type, Core::Frontend::ControllerParameters parameters) { switch (controller_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: return parameters.allow_pro_controller; case Core::HID::NpadStyleIndex::JoyconDual: return parameters.allow_dual_joycons; @@ -462,7 +462,7 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index }; if (npad_style_set.fullkey == 1) { - add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller")); + add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller")); } if (npad_style_set.joycon_dual == 1) { @@ -519,7 +519,7 @@ Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex [index](const auto& pair) { return pair.first == index; }); if (it == pairs.end()) { - return Core::HID::NpadStyleIndex::ProController; + return Core::HID::NpadStyleIndex::Fullkey; } return it->second; @@ -549,7 +549,7 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) const QString stylesheet = [this, player_index] { switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), player_index)) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::GameCube: return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); case Core::HID::NpadStyleIndex::JoyconDual: diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index bbe17c35e..ac81ace9e 100644 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -832,7 +832,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { }(); switch (controller_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::GameCube: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index f3552191a..5dac9f1e7 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -1094,7 +1094,7 @@ void ConfigureInputPlayer::SetConnectableControllers() { }; if (npad_style_set.fullkey == 1) { - add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller")); + add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller")); } if (npad_style_set.joycon_dual == 1) { @@ -1149,7 +1149,7 @@ Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int i [index](const auto& pair) { return pair.first == index; }); if (it == index_controller_type_pairs.end()) { - return Core::HID::NpadStyleIndex::ProController; + return Core::HID::NpadStyleIndex::Fullkey; } return it->second; @@ -1178,7 +1178,7 @@ void ConfigureInputPlayer::UpdateInputDevices() { void ConfigureInputPlayer::UpdateControllerAvailableButtons() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadStyleIndex::ProController; + layout = Core::HID::NpadStyleIndex::Fullkey; } // List of all the widgets that will be hidden by any of the following layouts that need @@ -1206,7 +1206,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { std::vector<QWidget*> layout_hidden; switch (layout) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::Handheld: layout_hidden = { ui->buttonShoulderButtonsSLSRLeft, @@ -1254,7 +1254,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { void ConfigureInputPlayer::UpdateControllerEnabledButtons() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadStyleIndex::ProController; + layout = Core::HID::NpadStyleIndex::Fullkey; } // List of all the widgets that will be disabled by any of the following layouts that need @@ -1271,7 +1271,7 @@ void ConfigureInputPlayer::UpdateControllerEnabledButtons() { std::vector<QWidget*> layout_disable; switch (layout) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::JoyconLeft: @@ -1304,7 +1304,7 @@ void ConfigureInputPlayer::UpdateMotionButtons() { // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller. switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::JoyconLeft: case Core::HID::NpadStyleIndex::Handheld: // Show "Motion 1" and hide "Motion 2". @@ -1333,11 +1333,11 @@ void ConfigureInputPlayer::UpdateMotionButtons() { void ConfigureInputPlayer::UpdateControllerButtonNames() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadStyleIndex::ProController; + layout = Core::HID::NpadStyleIndex::Fullkey; } switch (layout) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::JoyconLeft: diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 19fdca7d3..8f91f5e92 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -244,7 +244,7 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) { case Core::HID::NpadStyleIndex::GameCube: DrawGCController(p, center); break; - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: default: DrawProController(p, center); break; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 4f4c75f5c..fd5342537 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3988,7 +3988,7 @@ void GMainWindow::OnToggleDockedMode() { tr("Handheld controller can't be used on docked mode. Pro " "controller will be selected.")); handheld->Disconnect(); - player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); + player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey); player_1->Connect(); controller_dialog->refreshConfiguration(); } diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp index 2690b075d..0dbfca243 100644 --- a/src/yuzu/util/controller_navigation.cpp +++ b/src/yuzu/util/controller_navigation.cpp @@ -66,7 +66,7 @@ void ControllerNavigation::ControllerUpdateButton() { } switch (controller_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::GameCube: @@ -116,7 +116,7 @@ void ControllerNavigation::ControllerUpdateStick() { } switch (controller_type) { - case Core::HID::NpadStyleIndex::ProController: + case Core::HID::NpadStyleIndex::Fullkey: case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::Handheld: case Core::HID::NpadStyleIndex::GameCube: |