Compare commits

..

1 Commits

Author SHA1 Message Date
Liam
2044a289f8 shader_recompiler: fix Offset operand usage for non-OpImage*Gather 2024-01-11 00:56:37 -05:00
80 changed files with 755 additions and 4052 deletions

View File

@@ -25,7 +25,7 @@ for f in $FILES_TO_LINT; do
"$CLANG_FORMAT" -i "$f"
done
DIFF=$(git -c core.fileMode=false diff)
DIFF=$(git diff)
if [ ! -z "$DIFF" ]; then
echo "!!! Not compliant to coding style, here is the fix:"

View File

@@ -228,33 +228,71 @@ dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
}
fun runGitCommand(command: List<String>): String {
return try {
ProcessBuilder(command)
fun getGitVersion(): String {
var versionName = "0.0"
try {
versionName = ProcessBuilder("git", "describe", "--always", "--long")
.directory(project.rootDir)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start().inputStream.bufferedReader().use { it.readText() }
.trim()
} catch (e: Exception) {
logger.error("Cannot find git")
""
}
}
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)?-[^-]+$"), "")
} catch (e: Exception) {
logger.error("Cannot find git, defaulting to dummy version number")
}
return versionName.ifEmpty { "0.0" }
if (System.getenv("GITHUB_ACTIONS") != null) {
val gitTag = System.getenv("GIT_TAG_NAME")
versionName = gitTag ?: versionName
}
return versionName
}
fun getGitHash(): String =
runGitCommand(listOf("git", "rev-parse", "--short", "HEAD")).ifEmpty { "dummy-hash" }
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()
fun getBranch(): String =
runGitCommand(listOf("git", "rev-parse", "--abbrev-ref", "HEAD")).ifEmpty { "dummy-hash" }
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 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
}
}

View File

@@ -1,33 +0,0 @@
// 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
}
}
}

View File

@@ -1,98 +0,0 @@
// 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()
}
}

View File

@@ -1,105 +0,0 @@
// 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 }
}

View File

@@ -5,28 +5,48 @@ 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 : AbstractDiffAdapter<Addon, AddonAdapter.AddonViewHolder>() {
class AddonAdapter : ListAdapter<Addon, AddonAdapter.AddonViewHolder>(
AsyncDifferConfig.Builder(DiffCallback()).build()
) {
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) :
AbstractViewHolder<Addon>(binding) {
override fun bind(model: Addon) {
RecyclerView.ViewHolder(binding.root) {
fun bind(addon: Addon) {
binding.root.setOnClickListener {
binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked
}
binding.title.text = model.title
binding.version.text = model.version
binding.title.text = addon.title
binding.version.text = addon.version
binding.addonSwitch.setOnCheckedChangeListener { _, checked ->
model.enabled = checked
addon.enabled = checked
}
binding.addonSwitch.isChecked = model.enabled
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
}
}
}

View File

@@ -4,11 +4,13 @@
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
@@ -17,58 +19,72 @@ 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, applets: List<Applet>) :
AbstractListAdapter<Applet, AppletAdapter.AppletViewHolder>(applets) {
class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) :
RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(),
View.OnClickListener {
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) :
AbstractViewHolder<Applet>(binding) {
override fun bind(model: Applet) {
binding.title.setText(model.titleId)
binding.description.setText(model.descriptionId)
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)
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.context.resources,
model.iconId,
applet.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)
}
}
}

View File

@@ -4,10 +4,12 @@
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
@@ -17,43 +19,54 @@ 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) :
AbstractListAdapter<CabinetMode, CabinetModeViewHolder>(
CabinetMode.values().copyOfRange(1, CabinetMode.entries.size).toList()
) {
RecyclerView.Adapter<CabinetModeViewHolder>(),
View.OnClickListener {
private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size)
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) :
AbstractViewHolder<CabinetMode>(binding) {
override fun bind(model: CabinetMode) {
RecyclerView.ViewHolder(binding.root) {
lateinit var cabinetMode: CabinetMode
init {
itemView.tag = this
}
fun bind(cabinetMode: CabinetMode) {
this.cabinetMode = cabinetMode
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
binding.icon.context.resources,
model.iconId,
cabinetMode.iconId,
binding.icon.context.theme
)
)
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)
binding.title.setText(cabinetMode.titleId)
}
}
}

View File

@@ -7,39 +7,65 @@ 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.viewholder.AbstractViewHolder
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
class DriverAdapter(private val driverViewModel: DriverViewModel) :
AbstractSingleSelectionList<Driver, DriverAdapter.DriverViewHolder>(
driverViewModel.driverList.value
ListAdapter<Pair<String, GpuDriverMetadata>, DriverAdapter.DriverViewHolder>(
AsyncDifferConfig.Builder(DiffCallback()).build()
) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder {
CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return DriverViewHolder(it) }
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)
}
inner class DriverViewHolder(val binding: CardDriverOptionBinding) :
AbstractViewHolder<Driver>(binding) {
override fun bind(model: Driver) {
RecyclerView.ViewHolder(binding.root) {
private lateinit var driverData: Pair<String, GpuDriverMetadata>
fun bind(driverData: Pair<String, GpuDriverMetadata>) {
this.driverData = driverData
val driver = driverData.second
binding.apply {
radioButton.isChecked = model.selected
radioButton.isChecked = driverViewModel.selectedDriver == bindingAdapterPosition
root.setOnClickListener {
selectItem(bindingAdapterPosition) {
driverViewModel.onDriverSelected(it)
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
}
onSelectDriver(bindingAdapterPosition)
}
buttonDelete.setOnClickListener {
removeSelectableItem(
bindingAdapterPosition
) { removedPosition: Int, selectedPosition: Int ->
driverViewModel.onDriverRemoved(removedPosition, selectedPosition)
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
}
onDeleteDriver(driverData, bindingAdapterPosition)
}
// Delay marquee by 3s
@@ -54,19 +80,38 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
},
3000
)
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 {
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
version.visibility = View.VISIBLE
description.visibility = View.VISIBLE
buttonDelete.visibility = View.VISIBLE
}
}
}
}
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
}
}
}

View File

@@ -8,14 +8,19 @@ 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) :
AbstractDiffAdapter<GameDir, FolderAdapter.FolderViewHolder>() {
ListAdapter<GameDir, FolderAdapter.FolderViewHolder>(
AsyncDifferConfig.Builder(DiffCallback()).build()
) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
@@ -24,11 +29,18 @@ 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) :
AbstractViewHolder<GameDir>(binding) {
override fun bind(model: GameDir) {
RecyclerView.ViewHolder(binding.root) {
private lateinit var gameDir: GameDir
fun bind(gameDir: GameDir) {
this.gameDir = gameDir
binding.apply {
path.text = Uri.parse(model.uriString).path
path.text = Uri.parse(gameDir.uriString).path
path.postDelayed(
{
path.isSelected = true
@@ -38,7 +50,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
)
buttonEdit.setOnClickListener {
GameFolderPropertiesDialogFragment.newInstance(model)
GameFolderPropertiesDialogFragment.newInstance(this@FolderViewHolder.gameDir)
.show(
activity.supportFragmentManager,
GameFolderPropertiesDialogFragment.TAG
@@ -46,9 +58,19 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
}
buttonDelete.setOnClickListener {
gamesViewModel.removeFolder(model)
gamesViewModel.removeFolder(this@FolderViewHolder.gameDir)
}
}
}
}
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
}
}
}

View File

@@ -9,6 +9,7 @@ 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
@@ -24,6 +25,10 @@ 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
@@ -31,26 +36,122 @@ 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) :
AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>() {
ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()),
View.OnClickListener,
View.OnLongClickListener {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return GameViewHolder(it) }
// 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
}
inner class GameViewHolder(val binding: CardGameBinding) :
AbstractViewHolder<Game>(binding) {
override fun bind(model: Game) {
binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
GameIconUtils.loadGameIcon(model, binding.imageGameScreen)
RecyclerView.ViewHolder(binding.root) {
lateinit var game: Game
binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ")
init {
binding.cardGame.tag = this
}
fun bind(game: Game) {
this.game = game
binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
GameIconUtils.loadGameIcon(game, binding.imageGameScreen)
binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ")
binding.textGameTitle.postDelayed(
{
@@ -59,79 +160,16 @@ 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)
}
fun onLongClick(game: Game): Boolean {
val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game)
binding.root.findNavController().navigate(action)
return true
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
return oldItem == newItem
}
}
}

View File

@@ -12,22 +12,23 @@ 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>
) : AbstractListAdapter<GameProperty, AbstractViewHolder<GameProperty>>(properties) {
) :
RecyclerView.Adapter<GamePropertiesAdapter.GamePropertyViewHolder>() {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): AbstractViewHolder<GameProperty> {
): GamePropertyViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
PropertyType.Submenu.ordinal -> {
@@ -50,6 +51,11 @@ 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
@@ -57,10 +63,14 @@ class GamePropertiesAdapter(
}
}
sealed class GamePropertyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
abstract fun bind(property: GameProperty)
}
inner class SubmenuPropertyViewHolder(val binding: CardSimpleOutlinedBinding) :
AbstractViewHolder<GameProperty>(binding) {
override fun bind(model: GameProperty) {
val submenuProperty = model as SubmenuProperty
GamePropertyViewHolder(binding.root) {
override fun bind(property: GameProperty) {
val submenuProperty = property as SubmenuProperty
binding.root.setOnClickListener {
submenuProperty.action.invoke()
@@ -98,9 +108,9 @@ class GamePropertiesAdapter(
}
inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) :
AbstractViewHolder<GameProperty>(binding) {
override fun bind(model: GameProperty) {
val installableProperty = model as InstallableProperty
GamePropertyViewHolder(binding.root) {
override fun bind(property: GameProperty) {
val installableProperty = property as InstallableProperty
binding.title.setText(installableProperty.titleId)
binding.description.setText(installableProperty.descriptionId)

View File

@@ -14,37 +14,69 @@ 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,
options: List<HomeSetting>
) : AbstractListAdapter<HomeSetting, HomeSettingAdapter.HomeOptionViewHolder>(options) {
var options: List<HomeSetting>
) :
RecyclerView.Adapter<HomeSettingAdapter.HomeOptionViewHolder>(),
View.OnClickListener {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder {
CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return HomeOptionViewHolder(it) }
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)
}
}
inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) :
AbstractViewHolder<HomeSetting>(binding) {
override fun bind(model: HomeSetting) {
binding.optionTitle.text = activity.resources.getString(model.titleId)
binding.optionDescription.text = activity.resources.getString(model.descriptionId)
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)
binding.optionIcon.setImageDrawable(
ResourcesCompat.getDrawable(
activity.resources,
model.iconId,
option.iconId,
activity.theme
)
)
when (model.titleId) {
when (option.titleId) {
R.string.get_early_access ->
binding.optionLayout.background =
ContextCompat.getDrawable(
@@ -53,7 +85,7 @@ class HomeSettingAdapter(
)
}
if (!model.isEnabled.invoke()) {
if (!option.isEnabled.invoke()) {
binding.optionTitle.alpha = 0.5f
binding.optionDescription.alpha = 0.5f
binding.optionIcon.alpha = 0.5f
@@ -61,7 +93,7 @@ class HomeSettingAdapter(
viewLifecycle.lifecycleScope.launch {
viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
model.details.collect { updateOptionDetails(it) }
option.details.collect { updateOptionDetails(it) }
}
}
binding.optionDetail.postDelayed(
@@ -71,20 +103,6 @@ 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) {

View File

@@ -6,33 +6,43 @@ 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(installables: List<Installable>) :
AbstractListAdapter<Installable, InstallableAdapter.InstallableViewHolder>(installables) {
class InstallableAdapter(private val installables: List<Installable>) :
RecyclerView.Adapter<InstallableAdapter.InstallableViewHolder>() {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): InstallableAdapter.InstallableViewHolder {
CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return InstallableViewHolder(it) }
val binding =
CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return InstallableViewHolder(binding)
}
inner class InstallableViewHolder(val binding: CardInstallableBinding) :
AbstractViewHolder<Installable>(binding) {
override fun bind(model: Installable) {
binding.title.setText(model.titleId)
binding.description.setText(model.descriptionId)
override fun getItemCount(): Int = installables.size
if (model.install != null) {
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)
if (installable.install != null) {
binding.buttonInstall.visibility = View.VISIBLE
binding.buttonInstall.setOnClickListener { model.install.invoke() }
binding.buttonInstall.setOnClickListener { installable.install.invoke() }
}
if (model.export != null) {
if (installable.export != null) {
binding.buttonExport.visibility = View.VISIBLE
binding.buttonExport.setOnClickListener { model.export.invoke() }
binding.buttonExport.setOnClickListener { installable.export.invoke() }
}
}
}

View File

@@ -7,33 +7,49 @@ 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, licenses: List<License>) :
AbstractListAdapter<License, LicenseAdapter.LicenseViewHolder>(licenses) {
class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) :
RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(),
View.OnClickListener {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder {
ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return LicenseViewHolder(it) }
val binding =
ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
binding.root.setOnClickListener(this)
return LicenseViewHolder(binding)
}
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 getItemCount(): Int = licenses.size
root.setOnClickListener { onClick(model) }
}
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
}
private fun onClick(license: License) {
LicenseBottomSheetDialogFragment.newInstance(license)
.show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG)
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
}
}
}

View File

@@ -10,6 +10,7 @@ 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
@@ -17,19 +18,31 @@ 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, pages: List<SetupPage>) :
AbstractListAdapter<SetupPage, SetupAdapter.SetupPageViewHolder>(pages) {
class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) :
RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder {
PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.also { return SetupPageViewHolder(it) }
val binding = PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return SetupPageViewHolder(binding)
}
override fun getItemCount(): Int = pages.size
override fun onBindViewHolder(holder: SetupPageViewHolder, position: Int) =
holder.bind(pages[position])
inner class SetupPageViewHolder(val binding: PageSetupBinding) :
AbstractViewHolder<SetupPage>(binding), SetupCallback {
override fun bind(model: SetupPage) {
if (model.stepCompleted.invoke() == StepState.COMPLETE) {
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) {
binding.buttonAction.visibility = View.INVISIBLE
binding.textConfirmation.visibility = View.VISIBLE
}
@@ -37,31 +50,31 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
binding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
activity.resources,
model.iconId,
page.iconId,
activity.theme
)
)
binding.textTitle.text = activity.resources.getString(model.titleId)
binding.textTitle.text = activity.resources.getString(page.titleId)
binding.textDescription.text =
Html.fromHtml(activity.resources.getString(model.descriptionId), 0)
Html.fromHtml(activity.resources.getString(page.descriptionId), 0)
binding.buttonAction.apply {
text = activity.resources.getString(model.buttonTextId)
if (model.buttonIconId != 0) {
text = activity.resources.getString(page.buttonTextId)
if (page.buttonIconId != 0) {
icon = ResourcesCompat.getDrawable(
activity.resources,
model.buttonIconId,
page.buttonIconId,
activity.theme
)
}
iconGravity =
if (model.leftAlignedIcon) {
if (page.leftAlignedIcon) {
MaterialButton.ICON_GRAVITY_START
} else {
MaterialButton.ICON_GRAVITY_END
}
setOnClickListener {
model.buttonAction.invoke(this@SetupPageViewHolder)
page.buttonAction.invoke(this@SetupPageViewHolder)
}
}
}

View File

@@ -76,8 +76,8 @@ class AboutFragment : Fragment() {
binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment)
}
binding.textVersionName.text = BuildConfig.VERSION_NAME
binding.textVersionName.setOnClickListener {
binding.textBuildHash.text = BuildConfig.GIT_HASH
binding.buttonBuildHash.setOnClickListener {
val clipBoard =
requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH)

View File

@@ -3,7 +3,6 @@
package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -14,26 +13,20 @@ 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.Dispatchers
import kotlinx.coroutines.flow.collectLatest
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
@@ -62,43 +55,12 @@ 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(
@@ -123,6 +85,25 @@ 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()
}
@@ -179,7 +160,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
@@ -196,21 +177,12 @@ class DriverManagerFragment : Fragment() {
val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
val driverInList =
driverViewModel.driverData.firstOrNull { it.second == driverData }
driverViewModel.driverList.value.firstOrNull { it.second == driverData }
if (driverInList != null) {
return@newInstance getString(R.string.driver_already_installed)
} else {
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)
}
}
driverViewModel.addDriver(Pair(driverPath, driverData))
driverViewModel.setNewDriverInstalled(true)
}
return@newInstance Any()
}.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)

View File

@@ -1,27 +0,0 @@
// 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 ?: ""
)
}
}

View File

@@ -9,7 +9,6 @@ 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
@@ -18,10 +17,11 @@ 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.model.Driver.Companion.toDriver
import org.yuzu.yuzu_emu.utils.FileUtil
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,81 +38,97 @@ class DriverViewModel : ViewModel() {
!loading && ready && !deleting
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false)
var driverData = GpuDriverHelper.getDrivers()
private val _driverList = MutableStateFlow(GpuDriverHelper.getDrivers())
val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList
private val _driverList = MutableStateFlow(emptyList<Driver>())
val driverList: StateFlow<List<Driver>> get() = _driverList
var previouslySelectedDriver = 0
var selectedDriver = -1
// 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 _showClearButton = MutableStateFlow(false)
val showClearButton = _showClearButton.asStateFlow()
private val _newDriverInstalled = MutableStateFlow(false)
val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled
private val driversToDelete = mutableListOf<String>()
val driversToDelete = mutableListOf<String>()
init {
updateDriverList()
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)
}
// 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)
}
updateDriverNameForGame(null)
}
fun reloadDriverData() {
_areDriversLoading.value = true
driverData = GpuDriverHelper.getDrivers()
updateDriverList()
_areDriversLoading.value = false
fun setSelectedDriverIndex(value: Int) {
if (selectedDriver != -1) {
previouslySelectedDriver = selectedDriver
}
selectedDriver = value
}
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))
fun setNewDriverInstalled(value: Boolean) {
_newDriverInstalled.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)
} else {
setSelectedDriverIndex(driverIndex)
}
_driverList.value = newDriverList
}
fun removeDriver(driverData: Pair<String, GpuDriverMetadata>) {
_driverList.value.remove(driverData)
}
fun onOpenDriverManager(game: Game?) {
if (game != null) {
SettingsFile.loadCustomConfig(game)
}
updateDriverList()
}
fun showClearButton(value: Boolean) {
_showClearButton.value = value
}
fun onDriverSelected(position: Int) {
if (position == 0) {
StringSetting.DRIVER_PATH.setString("")
val driverPath = StringSetting.DRIVER_PATH.getString()
if (driverPath.isEmpty()) {
setSelectedDriverIndex(0)
} else {
StringSetting.DRIVER_PATH.setString(driverData[position - 1].first)
findSelectedDriver(GpuDriverHelper.getMetadataFromZip(File(driverPath)))
}
}
fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) {
driversToDelete.add(driverData[removedPosition - 1].first)
driverData.removeAt(removedPosition - 1)
onDriverSelected(selectedPosition)
}
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()
@@ -165,6 +181,20 @@ 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
@@ -187,6 +217,7 @@ class DriverViewModel : ViewModel() {
private fun setDriverReady() {
_isDriverReady.value = true
updateName()
_selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
}
}

View File

@@ -1,9 +0,0 @@
// 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)
}

View File

@@ -41,7 +41,6 @@ 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
@@ -59,7 +58,6 @@ 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
@@ -691,7 +689,6 @@ 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)

View File

@@ -62,6 +62,9 @@ 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
}

View File

@@ -1,18 +0,0 @@
// 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)
}

View File

@@ -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::Fullkey);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
handheld->Disconnect();
}
}

View File

@@ -147,7 +147,7 @@
android:layout_marginHorizontal="20dp" />
<LinearLayout
android:id="@+id/button_version_name"
android:id="@+id/button_build_hash"
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_version_name"
android:id="@+id/text_build_hash"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@@ -148,7 +148,7 @@
android:layout_marginHorizontal="20dp" />
<LinearLayout
android:id="@+id/button_version_name"
android:id="@+id/button_build_hash"
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_version_name"
android:id="@+id/text_build_hash"
style="@style/TextAppearance.Material3.BodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@@ -1,11 +0,0 @@
<?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>

View File

@@ -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::Fullkey);
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
controller->Connect(true);
} else if (parameters.allow_dual_joycons) {
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);

View File

@@ -1498,7 +1498,7 @@ void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
bool check_device_index = false;
switch (vibration_device_handle.npad_type) {
case Core::HID::NpadStyleIndex::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::Handheld:
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::JoyconLeft:

View File

@@ -36,30 +36,6 @@ 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
@@ -80,8 +56,6 @@ 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
@@ -104,14 +78,6 @@ 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

View File

@@ -27,7 +27,7 @@ EmulatedController::~EmulatedController() = default;
NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) {
switch (type) {
case Settings::ControllerType::ProController:
return NpadStyleIndex::Fullkey;
return NpadStyleIndex::ProController;
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::Fullkey;
return NpadStyleIndex::ProController;
}
}
Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) {
switch (type) {
case NpadStyleIndex::Fullkey:
case NpadStyleIndex::ProController:
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::Fullkey);
SetNpadStyleIndex(NpadStyleIndex::ProController);
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::Fullkey) {
if (npad_type == NpadStyleIndex::ProController) {
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::Fullkey:
case NpadStyleIndex::ProController:
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::Fullkey);
SetNpadStyleIndex(NpadStyleIndex::ProController);
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::Fullkey);
SetNpadStyleIndex(NpadStyleIndex::ProController);
Connect();
return;
}
// Fallback Pro controllers to Dual joycon
if (npad_type == NpadStyleIndex::Fullkey && supported_style_tag.joycon_dual) {
if (npad_type == NpadStyleIndex::ProController && 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::Fullkey:
case NpadStyleIndex::ProController:
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::Fullkey:
case NpadStyleIndex::ProController:
return supported_style_tag.fullkey.As<bool>();
case NpadStyleIndex::Handheld:
return supported_style_tag.handheld.As<bool>();

View File

@@ -220,7 +220,6 @@ enum class NpadIdType : u32 {
};
enum class NpadInterfaceType : u8 {
None = 0,
Bluetooth = 1,
Rail = 2,
Usb = 3,
@@ -230,7 +229,7 @@ enum class NpadInterfaceType : u8 {
// This is nn::hid::NpadStyleIndex
enum class NpadStyleIndex : u8 {
None = 0,
Fullkey = 3,
ProController = 3,
Handheld = 4,
HandheldNES = 4,
JoyconDual = 5,

View File

@@ -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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::Handheld:
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::JoyconLeft:

View File

@@ -1,197 +0,0 @@
// 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

View File

@@ -1,49 +0,0 @@
// 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

View File

@@ -1,199 +0,0 @@
// 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

View File

@@ -1,75 +0,0 @@
// 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

View File

@@ -1,126 +0,0 @@
// 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

View File

@@ -1,56 +0,0 @@
// 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

View File

@@ -1,123 +0,0 @@
// 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

View File

@@ -1,43 +0,0 @@
// 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

View File

@@ -1,108 +0,0 @@
// 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

View File

@@ -1,52 +0,0 @@
// 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

View File

@@ -1,140 +0,0 @@
// 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

View File

@@ -1,57 +0,0 @@
// 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

View File

@@ -1,294 +0,0 @@
// 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

View File

@@ -1,123 +0,0 @@
// 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

View File

@@ -1,99 +0,0 @@
// 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

View File

@@ -1,47 +0,0 @@
// 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

View File

@@ -1,47 +0,0 @@
// 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

View File

@@ -1,37 +0,0 @@
// 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

View File

@@ -1,322 +0,0 @@
// 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

View File

@@ -1,86 +0,0 @@
// 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

View File

@@ -1,154 +0,0 @@
// 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

View File

@@ -1,61 +0,0 @@
// 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

View File

@@ -1,73 +0,0 @@
// 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

View File

@@ -1,51 +0,0 @@
// 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

View File

@@ -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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::Pokeball:
return controller.shared_memory->sixaxis_fullkey_properties;
case Core::HID::NpadStyleIndex::Handheld:

View File

@@ -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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
return style.fullkey.As<bool>();
case Core::HID::NpadStyleIndex::Handheld:
return style.handheld.As<bool>();

View File

@@ -252,103 +252,4 @@ 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

View File

@@ -1,80 +0,0 @@
// 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

View File

@@ -1,34 +0,0 @@
// 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

View File

@@ -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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::Pokeball:
return controller.sixaxis_fullkey;
case Core::HID::NpadStyleIndex::Handheld:

View File

@@ -1,106 +0,0 @@
// 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

View File

@@ -1,31 +0,0 @@
// 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

View File

@@ -1,80 +0,0 @@
// 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

View File

@@ -1,29 +0,0 @@
// 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

View File

@@ -1,30 +0,0 @@
// 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

View File

@@ -1,28 +0,0 @@
// 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

View File

@@ -1,84 +0,0 @@
// 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

View File

@@ -1,35 +0,0 @@
// 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

View File

@@ -12,6 +12,11 @@ namespace Shader::Backend::SPIRV {
namespace {
class ImageOperands {
public:
[[maybe_unused]] static constexpr bool ImageSampleOffsetAllowed = false;
[[maybe_unused]] static constexpr bool ImageGatherOffsetAllowed = true;
[[maybe_unused]] static constexpr bool ImageFetchOffsetAllowed = false;
[[maybe_unused]] static constexpr bool ImageGradientOffsetAllowed = false;
explicit ImageOperands(EmitContext& ctx, bool has_bias, bool has_lod, bool has_lod_clamp,
Id lod, const IR::Value& offset) {
if (has_bias) {
@@ -22,7 +27,7 @@ public:
const Id lod_value{has_lod_clamp ? ctx.OpCompositeExtract(ctx.F32[1], lod, 0) : lod};
Add(spv::ImageOperandsMask::Lod, lod_value);
}
AddOffset(ctx, offset);
AddOffset(ctx, offset, ImageSampleOffsetAllowed);
if (has_lod_clamp) {
const Id lod_clamp{has_bias ? ctx.OpCompositeExtract(ctx.F32[1], lod, 1) : lod};
Add(spv::ImageOperandsMask::MinLod, lod_clamp);
@@ -55,20 +60,17 @@ public:
Add(spv::ImageOperandsMask::ConstOffsets, offsets);
}
explicit ImageOperands(Id offset, Id lod, Id ms) {
explicit ImageOperands(Id lod, Id ms) {
if (Sirit::ValidId(lod)) {
Add(spv::ImageOperandsMask::Lod, lod);
}
if (Sirit::ValidId(offset)) {
Add(spv::ImageOperandsMask::Offset, offset);
}
if (Sirit::ValidId(ms)) {
Add(spv::ImageOperandsMask::Sample, ms);
}
}
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives,
u32 num_derivatives, Id offset, Id lod_clamp) {
u32 num_derivatives, const IR::Value& offset, Id lod_clamp) {
if (!Sirit::ValidId(derivatives)) {
throw LogicError("Derivatives must be present");
}
@@ -83,16 +85,14 @@ public:
const Id derivatives_Y{ctx.OpCompositeConstruct(
ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y);
if (Sirit::ValidId(offset)) {
Add(spv::ImageOperandsMask::Offset, offset);
}
AddOffset(ctx, offset, ImageGradientOffsetAllowed);
if (has_lod_clamp) {
Add(spv::ImageOperandsMask::MinLod, lod_clamp);
}
}
explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2,
Id offset, Id lod_clamp) {
const IR::Value& offset, Id lod_clamp) {
if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) {
throw LogicError("Derivatives must be present");
}
@@ -111,9 +111,7 @@ public:
const Id derivatives_id2{ctx.OpCompositeConstruct(
ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})};
Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2);
if (Sirit::ValidId(offset)) {
Add(spv::ImageOperandsMask::Offset, offset);
}
AddOffset(ctx, offset, ImageGradientOffsetAllowed);
if (has_lod_clamp) {
Add(spv::ImageOperandsMask::MinLod, lod_clamp);
}
@@ -132,7 +130,7 @@ public:
}
private:
void AddOffset(EmitContext& ctx, const IR::Value& offset) {
void AddOffset(EmitContext& ctx, const IR::Value& offset, bool runtime_offset_allowed) {
if (offset.IsEmpty()) {
return;
}
@@ -165,7 +163,9 @@ private:
break;
}
}
Add(spv::ImageOperandsMask::Offset, ctx.Def(offset));
if (runtime_offset_allowed) {
Add(spv::ImageOperandsMask::Offset, ctx.Def(offset));
}
}
void Add(spv::ImageOperandsMask new_mask, Id value) {
@@ -311,6 +311,37 @@ Id ImageGatherSubpixelOffset(EmitContext& ctx, const IR::TextureInstInfo& info,
return coords;
}
}
void AddOffsetToCoordinates(EmitContext& ctx, const IR::TextureInstInfo& info, Id& coords,
Id offset) {
if (!Sirit::ValidId(offset)) {
return;
}
Id result_type{};
switch (info.type) {
case TextureType::Buffer:
case TextureType::Color1D:
case TextureType::ColorArray1D: {
result_type = ctx.U32[1];
break;
}
case TextureType::Color2D:
case TextureType::Color2DRect:
case TextureType::ColorArray2D: {
result_type = ctx.U32[2];
break;
}
case TextureType::Color3D: {
result_type = ctx.U32[3];
break;
}
case TextureType::ColorCube:
case TextureType::ColorArrayCube:
return;
}
coords = ctx.OpIAdd(result_type, coords, offset);
}
} // Anonymous namespace
Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
@@ -496,6 +527,7 @@ Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
Id lod, Id ms) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
AddOffsetToCoordinates(ctx, info, coords, offset);
if (info.type == TextureType::Buffer) {
lod = Id{};
}
@@ -503,7 +535,7 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
// This image is multisampled, lod must be implicit
lod = Id{};
}
const ImageOperands operands(offset, lod, ms);
const ImageOperands operands(lod, ms);
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
}
@@ -548,13 +580,13 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
}
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivatives, Id offset, Id lod_clamp) {
Id derivatives, const IR::Value& offset, Id lod_clamp) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
const auto operands =
info.num_derivatives == 3
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, offset, {}, lod_clamp)
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives, offset,
lod_clamp);
const auto operands = info.num_derivatives == 3
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
ctx.Def(offset), {}, lod_clamp)
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
info.num_derivatives, offset, lod_clamp);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
Texture(ctx, info, index), coords, operands.Mask(), operands.Span());

View File

@@ -543,7 +543,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
const IR::Value& skip_mips);
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
Id derivatives, Id offset, Id lod_clamp);
Id derivatives, const IR::Value& offset, Id lod_clamp);
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index);

View File

@@ -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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey, tr("Pro Controller"));
add_item(Core::HID::NpadStyleIndex::ProController, 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::Fullkey;
return Core::HID::NpadStyleIndex::ProController;
}
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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::GameCube:
return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
case Core::HID::NpadStyleIndex::JoyconDual:

View File

@@ -832,7 +832,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
}();
switch (controller_type) {
case Core::HID::NpadStyleIndex::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::GameCube:
ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));

View File

@@ -1094,7 +1094,7 @@ void ConfigureInputPlayer::SetConnectableControllers() {
};
if (npad_style_set.fullkey == 1) {
add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller"));
add_item(Core::HID::NpadStyleIndex::ProController, 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::Fullkey;
return Core::HID::NpadStyleIndex::ProController;
}
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::Fullkey;
layout = Core::HID::NpadStyleIndex::ProController;
}
// 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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey;
layout = Core::HID::NpadStyleIndex::ProController;
}
// 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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey;
layout = Core::HID::NpadStyleIndex::ProController;
}
switch (layout) {
case Core::HID::NpadStyleIndex::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::Handheld:
case Core::HID::NpadStyleIndex::JoyconLeft:

View File

@@ -244,7 +244,7 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) {
case Core::HID::NpadStyleIndex::GameCube:
DrawGCController(p, center);
break;
case Core::HID::NpadStyleIndex::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
default:
DrawProController(p, center);
break;

View File

@@ -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::Fullkey);
player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
player_1->Connect();
controller_dialog->refreshConfiguration();
}

View File

@@ -66,7 +66,7 @@ void ControllerNavigation::ControllerUpdateButton() {
}
switch (controller_type) {
case Core::HID::NpadStyleIndex::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
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::Fullkey:
case Core::HID::NpadStyleIndex::ProController:
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::Handheld:
case Core::HID::NpadStyleIndex::GameCube: