Compare commits
2 Commits
android-19
...
android-18
Author | SHA1 | Date | |
---|---|---|---|
73f2201b18 | |||
bd9ae51ab8 |
@ -3,32 +3,38 @@
|
|||||||
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
|
# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
shopt -s nullglob globstar
|
if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop \
|
||||||
|
dist/*.svg dist/*.xml; then
|
||||||
if git grep -nrI '\s$' src **/*.yml **/*.txt **/*.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop dist/*.svg dist/*.xml; then
|
|
||||||
echo Trailing whitespace found, aborting
|
echo Trailing whitespace found, aborting
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Default clang-format points to default 3.5 version one
|
# Default clang-format points to default 3.5 version one
|
||||||
CLANG_FORMAT="${CLANG_FORMAT:-clang-format-15}"
|
CLANG_FORMAT=${CLANG_FORMAT:-clang-format-15}
|
||||||
"$CLANG_FORMAT" --version
|
$CLANG_FORMAT --version
|
||||||
|
|
||||||
|
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
|
||||||
|
# Get list of every file modified in this pull request
|
||||||
|
files_to_lint="$(git diff --name-only --diff-filter=ACMRTUXB $TRAVIS_COMMIT_RANGE | grep '^src/[^.]*[.]\(cpp\|h\)$' || true)"
|
||||||
|
else
|
||||||
|
# Check everything for branch pushes
|
||||||
|
files_to_lint="$(find src/ -name '*.cpp' -or -name '*.h')"
|
||||||
|
fi
|
||||||
|
|
||||||
# Turn off tracing for this because it's too verbose
|
# Turn off tracing for this because it's too verbose
|
||||||
set +x
|
set +x
|
||||||
|
|
||||||
# Check everything for branch pushes
|
for f in $files_to_lint; do
|
||||||
FILES_TO_LINT="$(find src/ -name '*.cpp' -or -name '*.h')"
|
d=$(diff -u "$f" <($CLANG_FORMAT "$f") || true)
|
||||||
|
if ! [ -z "$d" ]; then
|
||||||
for f in $FILES_TO_LINT; do
|
echo "!!! $f not compliant to coding style, here is the fix:"
|
||||||
echo "$f"
|
echo "$d"
|
||||||
"$CLANG_FORMAT" -i "$f"
|
fail=1
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
DIFF=$(git -c core.fileMode=false diff)
|
set -x
|
||||||
|
|
||||||
if [ ! -z "$DIFF" ]; then
|
if [ "$fail" = 1 ]; then
|
||||||
echo "!!! Not compliant to coding style, here is the fix:"
|
|
||||||
echo "$DIFF"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -9,7 +9,7 @@ chmod a+x ./.ci/scripts/linux/docker.sh
|
|||||||
sudo chown -R 1027 ./
|
sudo chown -R 1027 ./
|
||||||
|
|
||||||
# The environment variables listed below:
|
# The environment variables listed below:
|
||||||
# AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION
|
# AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION
|
||||||
# are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps
|
# are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps
|
||||||
|
|
||||||
docker run -e AZURECIREPO -e TITLEBARFORMATIDLE -e TITLEBARFORMATRUNNING -e DISPLAYVERSION -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh "$1"
|
docker run -e AZURECIREPO -e TITLEBARFORMATIDLE -e TITLEBARFORMATRUNNING -e DISPLAYVERSION -e ENABLE_COMPATIBILITY_REPORTING -e CCACHE_DIR=/yuzu/ccache -v "$(pwd):/yuzu" -w /yuzu yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.ci/scripts/linux/docker.sh "$1"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) <year> <owner>
|
Copyright (c) <year> <owner>
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) <year> <owner>.
|
Copyright (c) <year> <owner>.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ Mozilla Public License Version 2.0
|
|||||||
means any form of the work other than Source Code Form.
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
1.7. "Larger Work"
|
1.7. "Larger Work"
|
||||||
means a work that combines Covered Software with other material, in
|
means a work that combines Covered Software with other material, in
|
||||||
a separate file or files, that is not Covered Software.
|
a separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
1.8. "License"
|
1.8. "License"
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
| Pull Request | Commit | Title | Author | Merged? |
|
| Pull Request | Commit | Title | Author | Merged? |
|
||||||
|----|----|----|----|----|
|
|----|----|----|----|----|
|
||||||
| [12579](https://github.com/yuzu-emu/yuzu-android//pull/12579) | [`66ae60a9e`](https://github.com/yuzu-emu/yuzu-android//pull/12579/files) | Core: Implement Device Mapping & GPU SMMU | [FernandoS27](https://github.com/FernandoS27/) | Yes |
|
| [12579](https://github.com/yuzu-emu/yuzu-android//pull/12579) | [`66ae60a9e`](https://github.com/yuzu-emu/yuzu-android//pull/12579/files) | Core: Implement Device Mapping & GPU SMMU | [FernandoS27](https://github.com/FernandoS27/) | Yes |
|
||||||
| [12610](https://github.com/yuzu-emu/yuzu-android//pull/12610) | [`200b371d1`](https://github.com/yuzu-emu/yuzu-android//pull/12610/files) | server_manager: respond to session close correctly | [liamwhite](https://github.com/liamwhite/) | Yes |
|
|
||||||
| [12612](https://github.com/yuzu-emu/yuzu-android//pull/12612) | [`aae9eea53`](https://github.com/yuzu-emu/yuzu-android//pull/12612/files) | fsp-srv: use program registry for SetCurrentProcess | [liamwhite](https://github.com/liamwhite/) | Yes |
|
|
||||||
| [12652](https://github.com/yuzu-emu/yuzu-android//pull/12652) | [`2a0d707ce`](https://github.com/yuzu-emu/yuzu-android//pull/12652/files) | shader_recompiler: emulate 8-bit and 16-bit storage writes with cas loop | [liamwhite](https://github.com/liamwhite/) | Yes |
|
|
||||||
|
|
||||||
|
|
||||||
End of merge log. You can find the original README.md below the break.
|
End of merge log. You can find the original README.md below the break.
|
||||||
|
2
externals/ffmpeg/CMakeLists.txt
vendored
2
externals/ffmpeg/CMakeLists.txt
vendored
@ -138,7 +138,7 @@ if (NOT WIN32 AND NOT ANDROID)
|
|||||||
--cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
|
--cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
|
||||||
--sysroot=${SYSROOT}
|
--sysroot=${SYSROOT}
|
||||||
--target-os=android
|
--target-os=android
|
||||||
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
|
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
|
||||||
--extra-ldflags="-nostdlib"
|
--extra-ldflags="-nostdlib"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
2
externals/nx_tzdb/tzdb_to_nx
vendored
2
externals/nx_tzdb/tzdb_to_nx
vendored
Submodule externals/nx_tzdb/tzdb_to_nx updated: 404d390045...f6680093bc
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 }
|
|
||||||
}
|
|
@ -5,28 +5,48 @@ package org.yuzu.yuzu_emu.adapters
|
|||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
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.databinding.ListItemAddonBinding
|
||||||
import org.yuzu.yuzu_emu.model.Addon
|
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 {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder {
|
||||||
ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
.also { return AddonViewHolder(it) }
|
.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) :
|
inner class AddonViewHolder(val binding: ListItemAddonBinding) :
|
||||||
AbstractViewHolder<Addon>(binding) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
override fun bind(model: Addon) {
|
fun bind(addon: Addon) {
|
||||||
binding.root.setOnClickListener {
|
binding.root.setOnClickListener {
|
||||||
binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked
|
binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked
|
||||||
}
|
}
|
||||||
binding.title.text = model.title
|
binding.title.text = addon.title
|
||||||
binding.version.text = model.version
|
binding.version.text = addon.version
|
||||||
binding.addonSwitch.setOnCheckedChangeListener { _, checked ->
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
package org.yuzu.yuzu_emu.adapters
|
package org.yuzu.yuzu_emu.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
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.Applet
|
||||||
import org.yuzu.yuzu_emu.model.AppletInfo
|
import org.yuzu.yuzu_emu.model.AppletInfo
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class AppletAdapter(val activity: FragmentActivity, applets: List<Applet>) :
|
class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) :
|
||||||
AbstractListAdapter<Applet, AppletAdapter.AppletViewHolder>(applets) {
|
RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(),
|
||||||
|
View.OnClickListener {
|
||||||
|
|
||||||
override fun onCreateViewHolder(
|
override fun onCreateViewHolder(
|
||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
viewType: Int
|
viewType: Int
|
||||||
): AppletAdapter.AppletViewHolder {
|
): AppletAdapter.AppletViewHolder {
|
||||||
CardSimpleOutlinedBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
CardSimpleOutlinedBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
.apply { root.setOnClickListener(this@AppletAdapter) }
|
||||||
.also { return AppletViewHolder(it) }
|
.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) :
|
inner class AppletViewHolder(val binding: CardSimpleOutlinedBinding) :
|
||||||
AbstractViewHolder<Applet>(binding) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
override fun bind(model: Applet) {
|
lateinit var applet: Applet
|
||||||
binding.title.setText(model.titleId)
|
|
||||||
binding.description.setText(model.descriptionId)
|
init {
|
||||||
|
itemView.tag = this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bind(applet: Applet) {
|
||||||
|
this.applet = applet
|
||||||
|
|
||||||
|
binding.title.setText(applet.titleId)
|
||||||
|
binding.description.setText(applet.descriptionId)
|
||||||
binding.icon.setImageDrawable(
|
binding.icon.setImageDrawable(
|
||||||
ResourcesCompat.getDrawable(
|
ResourcesCompat.getDrawable(
|
||||||
binding.icon.context.resources,
|
binding.icon.context.resources,
|
||||||
model.iconId,
|
applet.iconId,
|
||||||
binding.icon.context.theme
|
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
package org.yuzu.yuzu_emu.adapters
|
package org.yuzu.yuzu_emu.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
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.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder
|
||||||
import org.yuzu.yuzu_emu.model.AppletInfo
|
import org.yuzu.yuzu_emu.model.AppletInfo
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class CabinetLauncherDialogAdapter(val fragment: Fragment) :
|
class CabinetLauncherDialogAdapter(val fragment: Fragment) :
|
||||||
AbstractListAdapter<CabinetMode, CabinetModeViewHolder>(
|
RecyclerView.Adapter<CabinetModeViewHolder>(),
|
||||||
CabinetMode.values().copyOfRange(1, CabinetMode.entries.size).toList()
|
View.OnClickListener {
|
||||||
) {
|
private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size)
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder {
|
||||||
DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
.apply { root.setOnClickListener(this@CabinetLauncherDialogAdapter) }
|
||||||
.also { return CabinetModeViewHolder(it) }
|
.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) :
|
inner class CabinetModeViewHolder(val binding: DialogListItemBinding) :
|
||||||
AbstractViewHolder<CabinetMode>(binding) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
override fun bind(model: CabinetMode) {
|
lateinit var cabinetMode: CabinetMode
|
||||||
|
|
||||||
|
init {
|
||||||
|
itemView.tag = this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bind(cabinetMode: CabinetMode) {
|
||||||
|
this.cabinetMode = cabinetMode
|
||||||
binding.icon.setImageDrawable(
|
binding.icon.setImageDrawable(
|
||||||
ResourcesCompat.getDrawable(
|
ResourcesCompat.getDrawable(
|
||||||
binding.icon.context.resources,
|
binding.icon.context.resources,
|
||||||
model.iconId,
|
cabinetMode.iconId,
|
||||||
binding.icon.context.theme
|
binding.icon.context.theme
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.title.setText(model.titleId)
|
binding.title.setText(cabinetMode.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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,39 +7,65 @@ import android.text.TextUtils
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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.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.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) :
|
class DriverAdapter(private val driverViewModel: DriverViewModel) :
|
||||||
AbstractSingleSelectionList<Driver, DriverAdapter.DriverViewHolder>(
|
ListAdapter<Pair<String, GpuDriverMetadata>, DriverAdapter.DriverViewHolder>(
|
||||||
driverViewModel.driverList.value
|
AsyncDifferConfig.Builder(DiffCallback()).build()
|
||||||
) {
|
) {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder {
|
||||||
CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
val binding =
|
||||||
.also { return DriverViewHolder(it) }
|
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) :
|
inner class DriverViewHolder(val binding: CardDriverOptionBinding) :
|
||||||
AbstractViewHolder<Driver>(binding) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
override fun bind(model: Driver) {
|
private lateinit var driverData: Pair<String, GpuDriverMetadata>
|
||||||
|
|
||||||
|
fun bind(driverData: Pair<String, GpuDriverMetadata>) {
|
||||||
|
this.driverData = driverData
|
||||||
|
val driver = driverData.second
|
||||||
|
|
||||||
binding.apply {
|
binding.apply {
|
||||||
radioButton.isChecked = model.selected
|
radioButton.isChecked = driverViewModel.selectedDriver == bindingAdapterPosition
|
||||||
root.setOnClickListener {
|
root.setOnClickListener {
|
||||||
selectItem(bindingAdapterPosition) {
|
onSelectDriver(bindingAdapterPosition)
|
||||||
driverViewModel.onDriverSelected(it)
|
|
||||||
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
buttonDelete.setOnClickListener {
|
buttonDelete.setOnClickListener {
|
||||||
removeSelectableItem(
|
onDeleteDriver(driverData, bindingAdapterPosition)
|
||||||
bindingAdapterPosition
|
|
||||||
) { removedPosition: Int, selectedPosition: Int ->
|
|
||||||
driverViewModel.onDriverRemoved(removedPosition, selectedPosition)
|
|
||||||
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay marquee by 3s
|
// Delay marquee by 3s
|
||||||
@ -54,19 +80,38 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
|
|||||||
},
|
},
|
||||||
3000
|
3000
|
||||||
)
|
)
|
||||||
title.text = model.title
|
if (driver.name == null) {
|
||||||
version.text = model.version
|
title.setText(R.string.system_gpu_driver)
|
||||||
description.text = model.description
|
description.text = ""
|
||||||
if (model.description.isNotEmpty()) {
|
version.text = ""
|
||||||
version.visibility = View.VISIBLE
|
|
||||||
description.visibility = View.VISIBLE
|
|
||||||
buttonDelete.visibility = View.VISIBLE
|
|
||||||
} else {
|
|
||||||
version.visibility = View.GONE
|
version.visibility = View.GONE
|
||||||
description.visibility = View.GONE
|
description.visibility = View.GONE
|
||||||
buttonDelete.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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,19 @@ import android.text.TextUtils
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.FragmentActivity
|
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.databinding.CardFolderBinding
|
||||||
import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment
|
import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment
|
||||||
import org.yuzu.yuzu_emu.model.GameDir
|
import org.yuzu.yuzu_emu.model.GameDir
|
||||||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) :
|
class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) :
|
||||||
AbstractDiffAdapter<GameDir, FolderAdapter.FolderViewHolder>() {
|
ListAdapter<GameDir, FolderAdapter.FolderViewHolder>(
|
||||||
|
AsyncDifferConfig.Builder(DiffCallback()).build()
|
||||||
|
) {
|
||||||
override fun onCreateViewHolder(
|
override fun onCreateViewHolder(
|
||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
viewType: Int
|
viewType: Int
|
||||||
@ -24,11 +29,18 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
|
|||||||
.also { return FolderViewHolder(it) }
|
.also { return FolderViewHolder(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: FolderAdapter.FolderViewHolder, position: Int) =
|
||||||
|
holder.bind(currentList[position])
|
||||||
|
|
||||||
inner class FolderViewHolder(val binding: CardFolderBinding) :
|
inner class FolderViewHolder(val binding: CardFolderBinding) :
|
||||||
AbstractViewHolder<GameDir>(binding) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
override fun bind(model: GameDir) {
|
private lateinit var gameDir: GameDir
|
||||||
|
|
||||||
|
fun bind(gameDir: GameDir) {
|
||||||
|
this.gameDir = gameDir
|
||||||
|
|
||||||
binding.apply {
|
binding.apply {
|
||||||
path.text = Uri.parse(model.uriString).path
|
path.text = Uri.parse(gameDir.uriString).path
|
||||||
path.postDelayed(
|
path.postDelayed(
|
||||||
{
|
{
|
||||||
path.isSelected = true
|
path.isSelected = true
|
||||||
@ -38,7 +50,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
|
|||||||
)
|
)
|
||||||
|
|
||||||
buttonEdit.setOnClickListener {
|
buttonEdit.setOnClickListener {
|
||||||
GameFolderPropertiesDialogFragment.newInstance(model)
|
GameFolderPropertiesDialogFragment.newInstance(this@FolderViewHolder.gameDir)
|
||||||
.show(
|
.show(
|
||||||
activity.supportFragmentManager,
|
activity.supportFragmentManager,
|
||||||
GameFolderPropertiesDialogFragment.TAG
|
GameFolderPropertiesDialogFragment.TAG
|
||||||
@ -46,9 +58,19 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
buttonDelete.setOnClickListener {
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import android.graphics.drawable.LayerDrawable
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
@ -24,6 +25,10 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.preference.PreferenceManager
|
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.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
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.R
|
||||||
import org.yuzu.yuzu_emu.YuzuApplication
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
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.databinding.CardGameBinding
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||||
import org.yuzu.yuzu_emu.utils.GameIconUtils
|
import org.yuzu.yuzu_emu.utils.GameIconUtils
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class GameAdapter(private val activity: AppCompatActivity) :
|
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 {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
|
||||||
CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
// Create a new view.
|
||||||
.also { return GameViewHolder(it) }
|
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) :
|
inner class GameViewHolder(val binding: CardGameBinding) :
|
||||||
AbstractViewHolder<Game>(binding) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
override fun bind(model: Game) {
|
lateinit var game: Game
|
||||||
binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
|
|
||||||
GameIconUtils.loadGameIcon(model, binding.imageGameScreen)
|
|
||||||
|
|
||||||
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(
|
binding.textGameTitle.postDelayed(
|
||||||
{
|
{
|
||||||
@ -59,79 +160,16 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
|||||||
},
|
},
|
||||||
3000
|
3000
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.cardGame.setOnClickListener { onClick(model) }
|
private class DiffCallback : DiffUtil.ItemCallback<Game>() {
|
||||||
binding.cardGame.setOnLongClickListener { onLongClick(model) }
|
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClick(game: Game) {
|
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||||
val gameExists = DocumentFile.fromSingleUri(
|
return oldItem == newItem
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,22 +12,23 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
|
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
|
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
|
||||||
import org.yuzu.yuzu_emu.model.GameProperty
|
import org.yuzu.yuzu_emu.model.GameProperty
|
||||||
import org.yuzu.yuzu_emu.model.InstallableProperty
|
import org.yuzu.yuzu_emu.model.InstallableProperty
|
||||||
import org.yuzu.yuzu_emu.model.SubmenuProperty
|
import org.yuzu.yuzu_emu.model.SubmenuProperty
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class GamePropertiesAdapter(
|
class GamePropertiesAdapter(
|
||||||
private val viewLifecycle: LifecycleOwner,
|
private val viewLifecycle: LifecycleOwner,
|
||||||
private var properties: List<GameProperty>
|
private var properties: List<GameProperty>
|
||||||
) : AbstractListAdapter<GameProperty, AbstractViewHolder<GameProperty>>(properties) {
|
) :
|
||||||
|
RecyclerView.Adapter<GamePropertiesAdapter.GamePropertyViewHolder>() {
|
||||||
override fun onCreateViewHolder(
|
override fun onCreateViewHolder(
|
||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
viewType: Int
|
viewType: Int
|
||||||
): AbstractViewHolder<GameProperty> {
|
): GamePropertyViewHolder {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
PropertyType.Submenu.ordinal -> {
|
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 {
|
override fun getItemViewType(position: Int): Int {
|
||||||
return when (properties[position]) {
|
return when (properties[position]) {
|
||||||
is SubmenuProperty -> PropertyType.Submenu.ordinal
|
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) :
|
inner class SubmenuPropertyViewHolder(val binding: CardSimpleOutlinedBinding) :
|
||||||
AbstractViewHolder<GameProperty>(binding) {
|
GamePropertyViewHolder(binding.root) {
|
||||||
override fun bind(model: GameProperty) {
|
override fun bind(property: GameProperty) {
|
||||||
val submenuProperty = model as SubmenuProperty
|
val submenuProperty = property as SubmenuProperty
|
||||||
|
|
||||||
binding.root.setOnClickListener {
|
binding.root.setOnClickListener {
|
||||||
submenuProperty.action.invoke()
|
submenuProperty.action.invoke()
|
||||||
@ -98,9 +108,9 @@ class GamePropertiesAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) :
|
inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) :
|
||||||
AbstractViewHolder<GameProperty>(binding) {
|
GamePropertyViewHolder(binding.root) {
|
||||||
override fun bind(model: GameProperty) {
|
override fun bind(property: GameProperty) {
|
||||||
val installableProperty = model as InstallableProperty
|
val installableProperty = property as InstallableProperty
|
||||||
|
|
||||||
binding.title.setText(installableProperty.titleId)
|
binding.title.setText(installableProperty.titleId)
|
||||||
binding.description.setText(installableProperty.descriptionId)
|
binding.description.setText(installableProperty.descriptionId)
|
||||||
|
@ -14,37 +14,69 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
|
import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
import org.yuzu.yuzu_emu.model.HomeSetting
|
import org.yuzu.yuzu_emu.model.HomeSetting
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class HomeSettingAdapter(
|
class HomeSettingAdapter(
|
||||||
private val activity: AppCompatActivity,
|
private val activity: AppCompatActivity,
|
||||||
private val viewLifecycle: LifecycleOwner,
|
private val viewLifecycle: LifecycleOwner,
|
||||||
options: List<HomeSetting>
|
var options: List<HomeSetting>
|
||||||
) : AbstractListAdapter<HomeSetting, HomeSettingAdapter.HomeOptionViewHolder>(options) {
|
) :
|
||||||
|
RecyclerView.Adapter<HomeSettingAdapter.HomeOptionViewHolder>(),
|
||||||
|
View.OnClickListener {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder {
|
||||||
CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
val binding =
|
||||||
.also { return HomeOptionViewHolder(it) }
|
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) :
|
inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) :
|
||||||
AbstractViewHolder<HomeSetting>(binding) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
override fun bind(model: HomeSetting) {
|
lateinit var option: HomeSetting
|
||||||
binding.optionTitle.text = activity.resources.getString(model.titleId)
|
|
||||||
binding.optionDescription.text = activity.resources.getString(model.descriptionId)
|
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(
|
binding.optionIcon.setImageDrawable(
|
||||||
ResourcesCompat.getDrawable(
|
ResourcesCompat.getDrawable(
|
||||||
activity.resources,
|
activity.resources,
|
||||||
model.iconId,
|
option.iconId,
|
||||||
activity.theme
|
activity.theme
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
when (model.titleId) {
|
when (option.titleId) {
|
||||||
R.string.get_early_access ->
|
R.string.get_early_access ->
|
||||||
binding.optionLayout.background =
|
binding.optionLayout.background =
|
||||||
ContextCompat.getDrawable(
|
ContextCompat.getDrawable(
|
||||||
@ -53,7 +85,7 @@ class HomeSettingAdapter(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!model.isEnabled.invoke()) {
|
if (!option.isEnabled.invoke()) {
|
||||||
binding.optionTitle.alpha = 0.5f
|
binding.optionTitle.alpha = 0.5f
|
||||||
binding.optionDescription.alpha = 0.5f
|
binding.optionDescription.alpha = 0.5f
|
||||||
binding.optionIcon.alpha = 0.5f
|
binding.optionIcon.alpha = 0.5f
|
||||||
@ -61,7 +93,7 @@ class HomeSettingAdapter(
|
|||||||
|
|
||||||
viewLifecycle.lifecycleScope.launch {
|
viewLifecycle.lifecycleScope.launch {
|
||||||
viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
|
viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||||
model.details.collect { updateOptionDetails(it) }
|
option.details.collect { updateOptionDetails(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
binding.optionDetail.postDelayed(
|
binding.optionDetail.postDelayed(
|
||||||
@ -71,20 +103,6 @@ class HomeSettingAdapter(
|
|||||||
},
|
},
|
||||||
3000
|
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) {
|
private fun updateOptionDetails(detailString: String) {
|
||||||
|
@ -6,33 +6,43 @@ package org.yuzu.yuzu_emu.adapters
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
|
import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
|
||||||
import org.yuzu.yuzu_emu.model.Installable
|
import org.yuzu.yuzu_emu.model.Installable
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class InstallableAdapter(installables: List<Installable>) :
|
class InstallableAdapter(private val installables: List<Installable>) :
|
||||||
AbstractListAdapter<Installable, InstallableAdapter.InstallableViewHolder>(installables) {
|
RecyclerView.Adapter<InstallableAdapter.InstallableViewHolder>() {
|
||||||
override fun onCreateViewHolder(
|
override fun onCreateViewHolder(
|
||||||
parent: ViewGroup,
|
parent: ViewGroup,
|
||||||
viewType: Int
|
viewType: Int
|
||||||
): InstallableAdapter.InstallableViewHolder {
|
): InstallableAdapter.InstallableViewHolder {
|
||||||
CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
val binding =
|
||||||
.also { return InstallableViewHolder(it) }
|
CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return InstallableViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class InstallableViewHolder(val binding: CardInstallableBinding) :
|
override fun getItemCount(): Int = installables.size
|
||||||
AbstractViewHolder<Installable>(binding) {
|
|
||||||
override fun bind(model: Installable) {
|
|
||||||
binding.title.setText(model.titleId)
|
|
||||||
binding.description.setText(model.descriptionId)
|
|
||||||
|
|
||||||
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.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.visibility = View.VISIBLE
|
||||||
binding.buttonExport.setOnClickListener { model.export.invoke() }
|
binding.buttonExport.setOnClickListener { installable.export.invoke() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,33 +7,49 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
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.databinding.ListItemSettingBinding
|
||||||
import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
|
import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
|
||||||
import org.yuzu.yuzu_emu.model.License
|
import org.yuzu.yuzu_emu.model.License
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) :
|
class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) :
|
||||||
AbstractListAdapter<License, LicenseAdapter.LicenseViewHolder>(licenses) {
|
RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(),
|
||||||
|
View.OnClickListener {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder {
|
||||||
ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
val binding =
|
||||||
.also { return LicenseViewHolder(it) }
|
ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
binding.root.setOnClickListener(this)
|
||||||
|
return LicenseViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class LicenseViewHolder(val binding: ListItemSettingBinding) :
|
override fun getItemCount(): Int = licenses.size
|
||||||
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
|
|
||||||
|
|
||||||
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) {
|
fun bind(license: License) {
|
||||||
LicenseBottomSheetDialogFragment.newInstance(license)
|
this.license = license
|
||||||
.show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG)
|
|
||||||
|
val context = YuzuApplication.appContext
|
||||||
|
binding.textSettingName.text = context.getString(license.titleId)
|
||||||
|
binding.textSettingDescription.text = context.getString(license.descriptionId)
|
||||||
|
binding.textSettingValue.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import android.view.ViewGroup
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import org.yuzu.yuzu_emu.databinding.PageSetupBinding
|
import org.yuzu.yuzu_emu.databinding.PageSetupBinding
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
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.SetupPage
|
||||||
import org.yuzu.yuzu_emu.model.StepState
|
import org.yuzu.yuzu_emu.model.StepState
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils
|
import org.yuzu.yuzu_emu.utils.ViewUtils
|
||||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
|
||||||
|
|
||||||
class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
|
class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) :
|
||||||
AbstractListAdapter<SetupPage, SetupAdapter.SetupPageViewHolder>(pages) {
|
RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder {
|
||||||
PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
val binding = PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
.also { return SetupPageViewHolder(it) }
|
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) :
|
inner class SetupPageViewHolder(val binding: PageSetupBinding) :
|
||||||
AbstractViewHolder<SetupPage>(binding), SetupCallback {
|
RecyclerView.ViewHolder(binding.root), SetupCallback {
|
||||||
override fun bind(model: SetupPage) {
|
lateinit var page: SetupPage
|
||||||
if (model.stepCompleted.invoke() == StepState.COMPLETE) {
|
|
||||||
|
init {
|
||||||
|
itemView.tag = this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bind(page: SetupPage) {
|
||||||
|
this.page = page
|
||||||
|
|
||||||
|
if (page.stepCompleted.invoke() == StepState.COMPLETE) {
|
||||||
binding.buttonAction.visibility = View.INVISIBLE
|
binding.buttonAction.visibility = View.INVISIBLE
|
||||||
binding.textConfirmation.visibility = View.VISIBLE
|
binding.textConfirmation.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
@ -37,31 +50,31 @@ class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
|
|||||||
binding.icon.setImageDrawable(
|
binding.icon.setImageDrawable(
|
||||||
ResourcesCompat.getDrawable(
|
ResourcesCompat.getDrawable(
|
||||||
activity.resources,
|
activity.resources,
|
||||||
model.iconId,
|
page.iconId,
|
||||||
activity.theme
|
activity.theme
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.textTitle.text = activity.resources.getString(model.titleId)
|
binding.textTitle.text = activity.resources.getString(page.titleId)
|
||||||
binding.textDescription.text =
|
binding.textDescription.text =
|
||||||
Html.fromHtml(activity.resources.getString(model.descriptionId), 0)
|
Html.fromHtml(activity.resources.getString(page.descriptionId), 0)
|
||||||
|
|
||||||
binding.buttonAction.apply {
|
binding.buttonAction.apply {
|
||||||
text = activity.resources.getString(model.buttonTextId)
|
text = activity.resources.getString(page.buttonTextId)
|
||||||
if (model.buttonIconId != 0) {
|
if (page.buttonIconId != 0) {
|
||||||
icon = ResourcesCompat.getDrawable(
|
icon = ResourcesCompat.getDrawable(
|
||||||
activity.resources,
|
activity.resources,
|
||||||
model.buttonIconId,
|
page.buttonIconId,
|
||||||
activity.theme
|
activity.theme
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
iconGravity =
|
iconGravity =
|
||||||
if (model.leftAlignedIcon) {
|
if (page.leftAlignedIcon) {
|
||||||
MaterialButton.ICON_GRAVITY_START
|
MaterialButton.ICON_GRAVITY_START
|
||||||
} else {
|
} else {
|
||||||
MaterialButton.ICON_GRAVITY_END
|
MaterialButton.ICON_GRAVITY_END
|
||||||
}
|
}
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
model.buttonAction.invoke(this@SetupPageViewHolder)
|
page.buttonAction.invoke(this@SetupPageViewHolder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
package org.yuzu.yuzu_emu.fragments
|
package org.yuzu.yuzu_emu.fragments
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -14,26 +13,20 @@ import androidx.core.view.WindowInsetsCompat
|
|||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.adapters.DriverAdapter
|
import org.yuzu.yuzu_emu.adapters.DriverAdapter
|
||||||
import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding
|
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.DriverViewModel
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
import org.yuzu.yuzu_emu.utils.FileUtil
|
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||||
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@ -62,43 +55,12 @@ class DriverManagerFragment : Fragment() {
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is using the correct scope, lint is just acting up
|
|
||||||
@SuppressLint("UnsafeRepeatOnLifecycleDetector")
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
homeViewModel.setNavigationVisibility(visible = false, animated = true)
|
||||||
homeViewModel.setStatusBarShadeVisibility(visible = false)
|
homeViewModel.setStatusBarShadeVisibility(visible = false)
|
||||||
|
|
||||||
driverViewModel.onOpenDriverManager(args.game)
|
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) {
|
if (!driverViewModel.isInteractionAllowed.value) {
|
||||||
DriversLoadingDialogFragment().show(
|
DriversLoadingDialogFragment().show(
|
||||||
@ -123,6 +85,25 @@ class DriverManagerFragment : Fragment() {
|
|||||||
adapter = DriverAdapter(driverViewModel)
|
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()
|
setInsets()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +160,7 @@ class DriverManagerFragment : Fragment() {
|
|||||||
false
|
false
|
||||||
) {
|
) {
|
||||||
val driverPath =
|
val driverPath =
|
||||||
"${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(result)}"
|
"${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}"
|
||||||
val driverFile = File(driverPath)
|
val driverFile = File(driverPath)
|
||||||
|
|
||||||
// Ignore file exceptions when a user selects an invalid zip
|
// Ignore file exceptions when a user selects an invalid zip
|
||||||
@ -196,21 +177,12 @@ class DriverManagerFragment : Fragment() {
|
|||||||
|
|
||||||
val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
|
val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
|
||||||
val driverInList =
|
val driverInList =
|
||||||
driverViewModel.driverData.firstOrNull { it.second == driverData }
|
driverViewModel.driverList.value.firstOrNull { it.second == driverData }
|
||||||
if (driverInList != null) {
|
if (driverInList != null) {
|
||||||
return@newInstance getString(R.string.driver_already_installed)
|
return@newInstance getString(R.string.driver_already_installed)
|
||||||
} else {
|
} else {
|
||||||
driverViewModel.onDriverAdded(Pair(driverPath, driverData))
|
driverViewModel.addDriver(Pair(driverPath, driverData))
|
||||||
withContext(Dispatchers.Main) {
|
driverViewModel.setNewDriverInstalled(true)
|
||||||
if (_binding != null) {
|
|
||||||
val adapter = binding.listDrivers.adapter as DriverAdapter
|
|
||||||
adapter.addItem(driverData.toDriver())
|
|
||||||
adapter.selectItem(adapter.currentList.indices.last)
|
|
||||||
driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
|
|
||||||
binding.listDrivers
|
|
||||||
.smoothScrollToPosition(adapter.currentList.indices.last)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return@newInstance Any()
|
return@newInstance Any()
|
||||||
}.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
}.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
||||||
|
@ -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 ?: ""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,7 +9,6 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
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.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
|
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.GpuDriverHelper
|
||||||
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
|
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
|
import java.io.BufferedOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class DriverViewModel : ViewModel() {
|
class DriverViewModel : ViewModel() {
|
||||||
@ -38,81 +38,97 @@ class DriverViewModel : ViewModel() {
|
|||||||
!loading && ready && !deleting
|
!loading && ready && !deleting
|
||||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false)
|
}.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>())
|
var previouslySelectedDriver = 0
|
||||||
val driverList: StateFlow<List<Driver>> get() = _driverList
|
var selectedDriver = -1
|
||||||
|
|
||||||
// Used for showing which driver is currently installed within the driver manager card
|
// Used for showing which driver is currently installed within the driver manager card
|
||||||
private val _selectedDriverTitle = MutableStateFlow("")
|
private val _selectedDriverTitle = MutableStateFlow("")
|
||||||
val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle
|
val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle
|
||||||
|
|
||||||
private val _showClearButton = MutableStateFlow(false)
|
private val _newDriverInstalled = MutableStateFlow(false)
|
||||||
val showClearButton = _showClearButton.asStateFlow()
|
val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled
|
||||||
|
|
||||||
private val driversToDelete = mutableListOf<String>()
|
val driversToDelete = mutableListOf<String>()
|
||||||
|
|
||||||
init {
|
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)
|
updateDriverNameForGame(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reloadDriverData() {
|
fun setSelectedDriverIndex(value: Int) {
|
||||||
_areDriversLoading.value = true
|
if (selectedDriver != -1) {
|
||||||
driverData = GpuDriverHelper.getDrivers()
|
previouslySelectedDriver = selectedDriver
|
||||||
updateDriverList()
|
}
|
||||||
_areDriversLoading.value = false
|
selectedDriver = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateDriverList() {
|
fun setNewDriverInstalled(value: Boolean) {
|
||||||
val selectedDriver = GpuDriverHelper.customDriverSettingData
|
_newDriverInstalled.value = value
|
||||||
val newDriverList = mutableListOf(
|
}
|
||||||
Driver(
|
|
||||||
selectedDriver == GpuDriverMetadata(),
|
fun addDriver(driverData: Pair<String, GpuDriverMetadata>) {
|
||||||
YuzuApplication.appContext.getString(R.string.system_gpu_driver)
|
val driverIndex = _driverList.value.indexOfFirst { it == driverData }
|
||||||
)
|
if (driverIndex == -1) {
|
||||||
)
|
_driverList.value.add(driverData)
|
||||||
driverData.forEach {
|
setSelectedDriverIndex(_driverList.value.size - 1)
|
||||||
newDriverList.add(it.second.toDriver(it.second == selectedDriver))
|
_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?) {
|
fun onOpenDriverManager(game: Game?) {
|
||||||
if (game != null) {
|
if (game != null) {
|
||||||
SettingsFile.loadCustomConfig(game)
|
SettingsFile.loadCustomConfig(game)
|
||||||
}
|
}
|
||||||
updateDriverList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun showClearButton(value: Boolean) {
|
val driverPath = StringSetting.DRIVER_PATH.getString()
|
||||||
_showClearButton.value = value
|
if (driverPath.isEmpty()) {
|
||||||
}
|
setSelectedDriverIndex(0)
|
||||||
|
|
||||||
fun onDriverSelected(position: Int) {
|
|
||||||
if (position == 0) {
|
|
||||||
StringSetting.DRIVER_PATH.setString("")
|
|
||||||
} else {
|
} 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?) {
|
fun onCloseDriverManager(game: Game?) {
|
||||||
_isDeletingDrivers.value = true
|
_isDeletingDrivers.value = true
|
||||||
|
StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first)
|
||||||
updateDriverNameForGame(game)
|
updateDriverNameForGame(game)
|
||||||
if (game == null) {
|
if (game == null) {
|
||||||
NativeConfig.saveGlobalConfig()
|
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?) {
|
fun updateDriverNameForGame(game: Game?) {
|
||||||
if (!GpuDriverHelper.supportsCustomDriverLoading()) {
|
if (!GpuDriverHelper.supportsCustomDriverLoading()) {
|
||||||
return
|
return
|
||||||
@ -187,6 +217,7 @@ class DriverViewModel : ViewModel() {
|
|||||||
|
|
||||||
private fun setDriverReady() {
|
private fun setDriverReady() {
|
||||||
_isDriverReady.value = true
|
_isDriverReady.value = true
|
||||||
updateName()
|
_selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name
|
||||||
|
?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
|
@ -41,7 +41,6 @@ import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment
|
|||||||
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
|
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
|
||||||
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
|
||||||
import org.yuzu.yuzu_emu.model.AddonViewModel
|
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.GamesViewModel
|
||||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||||
import org.yuzu.yuzu_emu.model.TaskState
|
import org.yuzu.yuzu_emu.model.TaskState
|
||||||
@ -59,7 +58,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||||||
private val gamesViewModel: GamesViewModel by viewModels()
|
private val gamesViewModel: GamesViewModel by viewModels()
|
||||||
private val taskViewModel: TaskViewModel by viewModels()
|
private val taskViewModel: TaskViewModel by viewModels()
|
||||||
private val addonViewModel: AddonViewModel by viewModels()
|
private val addonViewModel: AddonViewModel by viewModels()
|
||||||
private val driverViewModel: DriverViewModel by viewModels()
|
|
||||||
|
|
||||||
override var themeId: Int = 0
|
override var themeId: Int = 0
|
||||||
|
|
||||||
@ -691,7 +689,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||||||
NativeLibrary.initializeSystem(true)
|
NativeLibrary.initializeSystem(true)
|
||||||
NativeConfig.initializeGlobalConfig()
|
NativeConfig.initializeGlobalConfig()
|
||||||
gamesViewModel.reloadGames(false)
|
gamesViewModel.reloadGames(false)
|
||||||
driverViewModel.reloadDriverData()
|
|
||||||
|
|
||||||
return@newInstance getString(R.string.user_data_import_success)
|
return@newInstance getString(R.string.user_data_import_success)
|
||||||
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
}.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
|
||||||
|
@ -62,6 +62,9 @@ object GpuDriverHelper {
|
|||||||
?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name }
|
?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name }
|
||||||
?.distinct()
|
?.distinct()
|
||||||
?.toMutableList() ?: mutableListOf()
|
?.toMutableList() ?: mutableListOf()
|
||||||
|
|
||||||
|
// TODO: Get system driver information
|
||||||
|
drivers.add(0, Pair("", GpuDriverMetadata()))
|
||||||
return drivers
|
return drivers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
}
|
|
@ -410,8 +410,8 @@ void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) {
|
|||||||
jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
|
||||||
|
|
||||||
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
|
if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
|
||||||
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
|
handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
|
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||||
handheld->Disconnect();
|
handheld->Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -770,8 +770,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
|
|||||||
ASSERT(user_id);
|
ASSERT(user_id);
|
||||||
|
|
||||||
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
||||||
{}, vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, 1,
|
EmulationSession::GetInstance().System(), vfs_nand_dir, FileSys::SaveDataSpaceId::NandUser,
|
||||||
user_id->AsU128(), 0);
|
FileSys::SaveDataType::SaveData, 1, user_id->AsU128(), 0);
|
||||||
|
|
||||||
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
|
const auto full_path = Common::FS::ConcatPathSafe(nand_dir, user_save_data_path);
|
||||||
if (!Common::FS::CreateParentDirs(full_path)) {
|
if (!Common::FS::CreateParentDirs(full_path)) {
|
||||||
@ -878,7 +878,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
|
|||||||
FileSys::Mode::Read);
|
FileSys::Mode::Read);
|
||||||
|
|
||||||
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
|
||||||
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
|
system, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
|
||||||
program_id, user_id->AsU128(), 0);
|
program_id, user_id->AsU128(), 0);
|
||||||
return ToJString(env, user_save_data_path);
|
return ToJString(env, user_save_data_path);
|
||||||
}
|
}
|
||||||
|
@ -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>
|
|
@ -492,10 +492,6 @@ add_library(core STATIC
|
|||||||
hle/service/filesystem/fsp_pr.h
|
hle/service/filesystem/fsp_pr.h
|
||||||
hle/service/filesystem/fsp_srv.cpp
|
hle/service/filesystem/fsp_srv.cpp
|
||||||
hle/service/filesystem/fsp_srv.h
|
hle/service/filesystem/fsp_srv.h
|
||||||
hle/service/filesystem/romfs_controller.cpp
|
|
||||||
hle/service/filesystem/romfs_controller.h
|
|
||||||
hle/service/filesystem/save_data_controller.cpp
|
|
||||||
hle/service/filesystem/save_data_controller.h
|
|
||||||
hle/service/fgm/fgm.cpp
|
hle/service/fgm/fgm.cpp
|
||||||
hle/service/fgm/fgm.h
|
hle/service/fgm/fgm.h
|
||||||
hle/service/friend/friend.cpp
|
hle/service/friend/friend.cpp
|
||||||
|
@ -414,7 +414,6 @@ struct System::Impl {
|
|||||||
kernel.ShutdownCores();
|
kernel.ShutdownCores();
|
||||||
services.reset();
|
services.reset();
|
||||||
service_manager.reset();
|
service_manager.reset();
|
||||||
fs_controller.Reset();
|
|
||||||
cheat_engine.reset();
|
cheat_engine.reset();
|
||||||
telemetry_session.reset();
|
telemetry_session.reset();
|
||||||
time_manager.Shutdown();
|
time_manager.Shutdown();
|
||||||
|
@ -97,9 +97,8 @@ std::string SaveDataAttribute::DebugInfo() const {
|
|||||||
static_cast<u8>(rank), index);
|
static_cast<u8>(rank), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveDataFactory::SaveDataFactory(Core::System& system_, ProgramId program_id_,
|
SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_directory_)
|
||||||
VirtualDir save_directory_)
|
: dir{std::move(save_directory_)}, system{system_} {
|
||||||
: system{system_}, program_id{program_id_}, dir{std::move(save_directory_)} {
|
|
||||||
// Delete all temporary storages
|
// Delete all temporary storages
|
||||||
// On hardware, it is expected that temporary storage be empty at first use.
|
// On hardware, it is expected that temporary storage be empty at first use.
|
||||||
dir->DeleteSubdirectoryRecursive("temp");
|
dir->DeleteSubdirectoryRecursive("temp");
|
||||||
@ -111,7 +110,7 @@ VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribut
|
|||||||
PrintSaveDataAttributeWarnings(meta);
|
PrintSaveDataAttributeWarnings(meta);
|
||||||
|
|
||||||
const auto save_directory =
|
const auto save_directory =
|
||||||
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||||
|
|
||||||
return dir->CreateDirectoryRelative(save_directory);
|
return dir->CreateDirectoryRelative(save_directory);
|
||||||
}
|
}
|
||||||
@ -119,7 +118,7 @@ VirtualDir SaveDataFactory::Create(SaveDataSpaceId space, const SaveDataAttribut
|
|||||||
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
VirtualDir SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const {
|
||||||
|
|
||||||
const auto save_directory =
|
const auto save_directory =
|
||||||
GetFullPath(program_id, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
GetFullPath(system, dir, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||||
|
|
||||||
auto out = dir->GetDirectoryRelative(save_directory);
|
auto out = dir->GetDirectoryRelative(save_directory);
|
||||||
|
|
||||||
@ -148,14 +147,14 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SaveDataFactory::GetFullPath(ProgramId program_id, VirtualDir dir,
|
std::string SaveDataFactory::GetFullPath(Core::System& system, VirtualDir dir,
|
||||||
SaveDataSpaceId space, SaveDataType type, u64 title_id,
|
SaveDataSpaceId space, SaveDataType type, u64 title_id,
|
||||||
u128 user_id, u64 save_id) {
|
u128 user_id, u64 save_id) {
|
||||||
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
|
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
|
||||||
// be interpreted as the title id of the current process.
|
// be interpreted as the title id of the current process.
|
||||||
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
|
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
|
||||||
if (title_id == 0) {
|
if (title_id == 0) {
|
||||||
title_id = program_id;
|
title_id = system.GetApplicationProcessProgramID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +201,7 @@ std::string SaveDataFactory::GetUserGameSaveDataRoot(u128 user_id, bool future)
|
|||||||
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||||
u128 user_id) const {
|
u128 user_id) const {
|
||||||
const auto path =
|
const auto path =
|
||||||
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||||
|
|
||||||
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
|
const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
|
||||||
@ -221,7 +220,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
|||||||
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||||
SaveDataSize new_value) const {
|
SaveDataSize new_value) const {
|
||||||
const auto path =
|
const auto path =
|
||||||
GetFullPath(program_id, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||||
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
|
||||||
|
|
||||||
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
|
||||||
|
@ -87,13 +87,10 @@ constexpr const char* GetSaveDataSizeFileName() {
|
|||||||
return ".yuzu_save_size";
|
return ".yuzu_save_size";
|
||||||
}
|
}
|
||||||
|
|
||||||
using ProgramId = u64;
|
|
||||||
|
|
||||||
/// File system interface to the SaveData archive
|
/// File system interface to the SaveData archive
|
||||||
class SaveDataFactory {
|
class SaveDataFactory {
|
||||||
public:
|
public:
|
||||||
explicit SaveDataFactory(Core::System& system_, ProgramId program_id_,
|
explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_);
|
||||||
VirtualDir save_directory_);
|
|
||||||
~SaveDataFactory();
|
~SaveDataFactory();
|
||||||
|
|
||||||
VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
|
VirtualDir Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
|
||||||
@ -102,7 +99,7 @@ public:
|
|||||||
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
|
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
|
||||||
|
|
||||||
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
|
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
|
||||||
static std::string GetFullPath(ProgramId program_id, VirtualDir dir, SaveDataSpaceId space,
|
static std::string GetFullPath(Core::System& system, VirtualDir dir, SaveDataSpaceId space,
|
||||||
SaveDataType type, u64 title_id, u128 user_id, u64 save_id);
|
SaveDataType type, u64 title_id, u128 user_id, u64 save_id);
|
||||||
static std::string GetUserGameSaveDataRoot(u128 user_id, bool future);
|
static std::string GetUserGameSaveDataRoot(u128 user_id, bool future);
|
||||||
|
|
||||||
@ -113,9 +110,8 @@ public:
|
|||||||
void SetAutoCreate(bool state);
|
void SetAutoCreate(bool state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Core::System& system;
|
|
||||||
ProgramId program_id;
|
|
||||||
VirtualDir dir;
|
VirtualDir dir;
|
||||||
|
Core::System& system;
|
||||||
bool auto_create{true};
|
bool auto_create{true};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
|
|||||||
// Connect controllers based on the following priority list from highest to lowest priority:
|
// Connect controllers based on the following priority list from highest to lowest priority:
|
||||||
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
|
||||||
if (parameters.allow_pro_controller) {
|
if (parameters.allow_pro_controller) {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
|
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
|
||||||
controller->Connect(true);
|
controller->Connect(true);
|
||||||
} else if (parameters.allow_dual_joycons) {
|
} else if (parameters.allow_dual_joycons) {
|
||||||
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
#include "core/hle/service/caps/caps_su.h"
|
#include "core/hle/service/caps/caps_su.h"
|
||||||
#include "core/hle/service/caps/caps_types.h"
|
#include "core/hle/service/caps/caps_types.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/hle/service/filesystem/save_data_controller.h"
|
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/hle/service/ns/ns.h"
|
#include "core/hle/service/ns/ns.h"
|
||||||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
||||||
@ -2179,7 +2178,7 @@ void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
|
|||||||
attribute.type = FileSys::SaveDataType::SaveData;
|
attribute.type = FileSys::SaveDataType::SaveData;
|
||||||
|
|
||||||
FileSys::VirtualDir save_data{};
|
FileSys::VirtualDir save_data{};
|
||||||
const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
|
const auto res = system.GetFileSystemController().CreateSaveData(
|
||||||
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
|
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
@ -2354,7 +2353,7 @@ void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) {
|
|||||||
"new_journal={:016X}",
|
"new_journal={:016X}",
|
||||||
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
|
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
|
||||||
|
|
||||||
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
|
system.GetFileSystemController().WriteSaveDataSize(
|
||||||
type, system.GetApplicationProcessProgramID(), user_id,
|
type, system.GetApplicationProcessProgramID(), user_id,
|
||||||
{new_normal_size, new_journal_size});
|
{new_normal_size, new_journal_size});
|
||||||
|
|
||||||
@ -2379,7 +2378,7 @@ void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
|
|||||||
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
|
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
|
||||||
user_id[0]);
|
user_id[0]);
|
||||||
|
|
||||||
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
|
const auto size = system.GetFileSystemController().ReadSaveDataSize(
|
||||||
type, system.GetApplicationProcessProgramID(), user_id);
|
type, system.GetApplicationProcessProgramID(), user_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 6};
|
IPC::ResponseBuilder rb{ctx, 6};
|
||||||
|
@ -24,13 +24,15 @@
|
|||||||
#include "core/hle/service/filesystem/fsp_ldr.h"
|
#include "core/hle/service/filesystem/fsp_ldr.h"
|
||||||
#include "core/hle/service/filesystem/fsp_pr.h"
|
#include "core/hle/service/filesystem/fsp_pr.h"
|
||||||
#include "core/hle/service/filesystem/fsp_srv.h"
|
#include "core/hle/service/filesystem/fsp_srv.h"
|
||||||
#include "core/hle/service/filesystem/romfs_controller.h"
|
|
||||||
#include "core/hle/service/filesystem/save_data_controller.h"
|
|
||||||
#include "core/hle/service/server_manager.h"
|
#include "core/hle/service/server_manager.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
namespace Service::FileSystem {
|
||||||
|
|
||||||
|
// A default size for normal/journal save data size if application control metadata cannot be found.
|
||||||
|
// This should be large enough to satisfy even the most extreme requirements (~4.2GB)
|
||||||
|
constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
|
||||||
|
|
||||||
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
|
||||||
std::string_view dir_name_) {
|
std::string_view dir_name_) {
|
||||||
std::string dir_name(Common::FS::SanitizePath(dir_name_));
|
std::string dir_name(Common::FS::SanitizePath(dir_name_));
|
||||||
@ -295,65 +297,145 @@ FileSystemController::FileSystemController(Core::System& system_) : system{syste
|
|||||||
|
|
||||||
FileSystemController::~FileSystemController() = default;
|
FileSystemController::~FileSystemController() = default;
|
||||||
|
|
||||||
Result FileSystemController::RegisterProcess(
|
Result FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
|
||||||
ProcessId process_id, ProgramId program_id,
|
romfs_factory = std::move(factory);
|
||||||
std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory) {
|
LOG_DEBUG(Service_FS, "Registered RomFS");
|
||||||
std::scoped_lock lk{registration_lock};
|
|
||||||
|
|
||||||
registrations.emplace(process_id, Registration{
|
|
||||||
.program_id = program_id,
|
|
||||||
.romfs_factory = std::move(romfs_factory),
|
|
||||||
.save_data_factory = CreateSaveDataFactory(program_id),
|
|
||||||
});
|
|
||||||
|
|
||||||
LOG_DEBUG(Service_FS, "Registered for process {}", process_id);
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileSystemController::OpenProcess(
|
Result FileSystemController::RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
|
||||||
ProgramId* out_program_id, std::shared_ptr<SaveDataController>* out_save_data_controller,
|
ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data");
|
||||||
std::shared_ptr<RomFsController>* out_romfs_controller, ProcessId process_id) {
|
save_data_factory = std::move(factory);
|
||||||
std::scoped_lock lk{registration_lock};
|
LOG_DEBUG(Service_FS, "Registered save data");
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
const auto it = registrations.find(process_id);
|
Result FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
|
||||||
if (it == registrations.end()) {
|
ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
|
||||||
|
sdmc_factory = std::move(factory);
|
||||||
|
LOG_DEBUG(Service_FS, "Registered SDMC");
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
|
||||||
|
ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
|
||||||
|
bis_factory = std::move(factory);
|
||||||
|
LOG_DEBUG(Service_FS, "Registered BIS");
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
|
||||||
|
LOG_TRACE(Service_FS, "Setting packed update for romfs");
|
||||||
|
|
||||||
|
if (romfs_factory == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
romfs_factory->SetPackedUpdate(std::move(update_raw));
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const {
|
||||||
|
LOG_TRACE(Service_FS, "Opening RomFS for current process");
|
||||||
|
|
||||||
|
if (romfs_factory == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID());
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id,
|
||||||
|
FileSys::ContentRecordType type) const {
|
||||||
|
LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id);
|
||||||
|
|
||||||
|
if (romfs_factory == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return romfs_factory->OpenPatchedRomFS(title_id, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex(
|
||||||
|
u64 title_id, u8 program_index, FileSys::ContentRecordType type) const {
|
||||||
|
LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id,
|
||||||
|
program_index);
|
||||||
|
|
||||||
|
if (romfs_factory == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::VirtualFile FileSystemController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||||
|
FileSys::ContentRecordType type) const {
|
||||||
|
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
|
||||||
|
title_id, storage_id, type);
|
||||||
|
|
||||||
|
if (romfs_factory == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return romfs_factory->Open(title_id, storage_id, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<FileSys::NCA> FileSystemController::OpenBaseNca(
|
||||||
|
u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
|
||||||
|
return romfs_factory->GetEntry(title_id, storage_id, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data,
|
||||||
|
FileSys::SaveDataSpaceId space,
|
||||||
|
const FileSys::SaveDataAttribute& save_struct) const {
|
||||||
|
LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
|
||||||
|
save_struct.DebugInfo());
|
||||||
|
|
||||||
|
if (save_data_factory == nullptr) {
|
||||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_program_id = it->second.program_id;
|
auto save_data = save_data_factory->Create(space, save_struct);
|
||||||
*out_save_data_controller =
|
if (save_data == nullptr) {
|
||||||
std::make_shared<SaveDataController>(system, it->second.save_data_factory);
|
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||||
*out_romfs_controller =
|
}
|
||||||
std::make_shared<RomFsController>(it->second.romfs_factory, it->second.program_id);
|
|
||||||
|
*out_save_data = save_data;
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystemController::SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw) {
|
Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data,
|
||||||
LOG_TRACE(Service_FS, "Setting packed update for romfs");
|
FileSys::SaveDataSpaceId space,
|
||||||
|
const FileSys::SaveDataAttribute& attribute) const {
|
||||||
|
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space,
|
||||||
|
attribute.DebugInfo());
|
||||||
|
|
||||||
std::scoped_lock lk{registration_lock};
|
if (save_data_factory == nullptr) {
|
||||||
const auto it = registrations.find(process_id);
|
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||||
if (it == registrations.end()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it->second.romfs_factory->SetPackedUpdate(std::move(update_raw));
|
auto save_data = save_data_factory->Open(space, attribute);
|
||||||
|
if (save_data == nullptr) {
|
||||||
|
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_save_data = save_data;
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController() {
|
Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
|
||||||
return std::make_shared<SaveDataController>(system, CreateSaveDataFactory(ProgramId{}));
|
FileSys::SaveDataSpaceId space) const {
|
||||||
}
|
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space);
|
||||||
|
|
||||||
std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory(
|
if (save_data_factory == nullptr) {
|
||||||
ProgramId program_id) {
|
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||||
using YuzuPath = Common::FS::YuzuPath;
|
}
|
||||||
const auto rw_mode = FileSys::Mode::ReadWrite;
|
|
||||||
|
|
||||||
auto vfs = system.GetFilesystem();
|
auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space);
|
||||||
const auto nand_directory =
|
if (save_data_space == nullptr) {
|
||||||
vfs->OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
|
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||||
return std::make_shared<FileSys::SaveDataFactory>(system, program_id,
|
}
|
||||||
std::move(nand_directory));
|
|
||||||
|
*out_save_data_space = save_data_space;
|
||||||
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
|
Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
|
||||||
@ -458,6 +540,48 @@ u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type,
|
||||||
|
u64 title_id, u128 user_id) const {
|
||||||
|
if (save_data_factory == nullptr) {
|
||||||
|
return {0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id);
|
||||||
|
|
||||||
|
if (value.normal == 0 && value.journal == 0) {
|
||||||
|
FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE};
|
||||||
|
|
||||||
|
FileSys::NACP nacp;
|
||||||
|
const auto res = system.GetAppLoader().ReadControlData(nacp);
|
||||||
|
|
||||||
|
if (res != Loader::ResultStatus::Success) {
|
||||||
|
const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
|
||||||
|
system.GetFileSystemController(),
|
||||||
|
system.GetContentProvider()};
|
||||||
|
const auto metadata = pm.GetControlMetadata();
|
||||||
|
const auto& nacp_unique = metadata.first;
|
||||||
|
|
||||||
|
if (nacp_unique != nullptr) {
|
||||||
|
new_size = {nacp_unique->GetDefaultNormalSaveSize(),
|
||||||
|
nacp_unique->GetDefaultJournalSaveSize()};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()};
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteSaveDataSize(type, title_id, user_id, new_size);
|
||||||
|
return new_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
||||||
|
FileSys::SaveDataSize new_value) const {
|
||||||
|
if (save_data_factory != nullptr)
|
||||||
|
save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
|
void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
|
||||||
gamecard = std::make_unique<FileSys::XCI>(file);
|
gamecard = std::make_unique<FileSys::XCI>(file);
|
||||||
const auto dir = gamecard->ConcatenatedPseudoDirectory();
|
const auto dir = gamecard->ConcatenatedPseudoDirectory();
|
||||||
@ -677,9 +801,14 @@ FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const {
|
|||||||
return bis_factory->GetBCATDirectory(title_id);
|
return bis_factory->GetBCATDirectory(title_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileSystemController::SetAutoSaveDataCreation(bool enable) {
|
||||||
|
save_data_factory->SetAutoCreate(enable);
|
||||||
|
}
|
||||||
|
|
||||||
void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
|
void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
|
||||||
if (overwrite) {
|
if (overwrite) {
|
||||||
bis_factory = nullptr;
|
bis_factory = nullptr;
|
||||||
|
save_data_factory = nullptr;
|
||||||
sdmc_factory = nullptr;
|
sdmc_factory = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,6 +836,11 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
|
|||||||
bis_factory->GetUserNANDContents());
|
bis_factory->GetUserNANDContents());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (save_data_factory == nullptr) {
|
||||||
|
save_data_factory =
|
||||||
|
std::make_unique<FileSys::SaveDataFactory>(system, std::move(nand_directory));
|
||||||
|
}
|
||||||
|
|
||||||
if (sdmc_factory == nullptr) {
|
if (sdmc_factory == nullptr) {
|
||||||
sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory),
|
sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory),
|
||||||
std::move(sd_load_directory));
|
std::move(sd_load_directory));
|
||||||
@ -715,19 +849,12 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystemController::Reset() {
|
|
||||||
std::scoped_lock lk{registration_lock};
|
|
||||||
registrations.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
const auto FileSystemProxyFactory = [&] { return std::make_shared<FSP_SRV>(system); };
|
|
||||||
|
|
||||||
server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system));
|
server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system));
|
||||||
server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system));
|
server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system));
|
||||||
server_manager->RegisterNamedService("fsp-srv", std::move(FileSystemProxyFactory));
|
server_manager->RegisterNamedService("fsp-srv", std::make_shared<FSP_SRV>(system));
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,9 +43,6 @@ class ServiceManager;
|
|||||||
|
|
||||||
namespace FileSystem {
|
namespace FileSystem {
|
||||||
|
|
||||||
class RomFsController;
|
|
||||||
class SaveDataController;
|
|
||||||
|
|
||||||
enum class ContentStorageId : u32 {
|
enum class ContentStorageId : u32 {
|
||||||
System,
|
System,
|
||||||
User,
|
User,
|
||||||
@ -64,24 +61,32 @@ enum class OpenDirectoryMode : u64 {
|
|||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode);
|
DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode);
|
||||||
|
|
||||||
using ProcessId = u64;
|
|
||||||
using ProgramId = u64;
|
|
||||||
|
|
||||||
class FileSystemController {
|
class FileSystemController {
|
||||||
public:
|
public:
|
||||||
explicit FileSystemController(Core::System& system_);
|
explicit FileSystemController(Core::System& system_);
|
||||||
~FileSystemController();
|
~FileSystemController();
|
||||||
|
|
||||||
Result RegisterProcess(ProcessId process_id, ProgramId program_id,
|
Result RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
|
||||||
std::shared_ptr<FileSys::RomFSFactory>&& factory);
|
Result RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
|
||||||
Result OpenProcess(ProgramId* out_program_id,
|
Result RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
|
||||||
std::shared_ptr<SaveDataController>* out_save_data_controller,
|
Result RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
|
||||||
std::shared_ptr<RomFsController>* out_romfs_controller,
|
|
||||||
ProcessId process_id);
|
|
||||||
void SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw);
|
|
||||||
|
|
||||||
std::shared_ptr<SaveDataController> OpenSaveDataController();
|
void SetPackedUpdate(FileSys::VirtualFile update_raw);
|
||||||
|
FileSys::VirtualFile OpenRomFSCurrentProcess() const;
|
||||||
|
FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type) const;
|
||||||
|
FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
|
||||||
|
FileSys::ContentRecordType type) const;
|
||||||
|
FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||||
|
FileSys::ContentRecordType type) const;
|
||||||
|
std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id,
|
||||||
|
FileSys::ContentRecordType type) const;
|
||||||
|
|
||||||
|
Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
|
||||||
|
const FileSys::SaveDataAttribute& save_struct) const;
|
||||||
|
Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
|
||||||
|
const FileSys::SaveDataAttribute& save_struct) const;
|
||||||
|
Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
|
||||||
|
FileSys::SaveDataSpaceId space) const;
|
||||||
Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const;
|
Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const;
|
||||||
Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
|
Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
|
||||||
FileSys::BisPartitionId id) const;
|
FileSys::BisPartitionId id) const;
|
||||||
@ -91,6 +96,11 @@ public:
|
|||||||
u64 GetFreeSpaceSize(FileSys::StorageId id) const;
|
u64 GetFreeSpaceSize(FileSys::StorageId id) const;
|
||||||
u64 GetTotalSpaceSize(FileSys::StorageId id) const;
|
u64 GetTotalSpaceSize(FileSys::StorageId id) const;
|
||||||
|
|
||||||
|
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
|
||||||
|
u128 user_id) const;
|
||||||
|
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
||||||
|
FileSys::SaveDataSize new_value) const;
|
||||||
|
|
||||||
void SetGameCard(FileSys::VirtualFile file);
|
void SetGameCard(FileSys::VirtualFile file);
|
||||||
FileSys::XCI* GetGameCard() const;
|
FileSys::XCI* GetGameCard() const;
|
||||||
|
|
||||||
@ -123,24 +133,15 @@ public:
|
|||||||
|
|
||||||
FileSys::VirtualDir GetBCATDirectory(u64 title_id) const;
|
FileSys::VirtualDir GetBCATDirectory(u64 title_id) const;
|
||||||
|
|
||||||
|
void SetAutoSaveDataCreation(bool enable);
|
||||||
|
|
||||||
// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
|
// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
|
||||||
// above is called.
|
// above is called.
|
||||||
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
|
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
|
||||||
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<FileSys::SaveDataFactory> CreateSaveDataFactory(ProgramId program_id);
|
std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
|
||||||
|
std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
|
||||||
struct Registration {
|
|
||||||
ProgramId program_id;
|
|
||||||
std::shared_ptr<FileSys::RomFSFactory> romfs_factory;
|
|
||||||
std::shared_ptr<FileSys::SaveDataFactory> save_data_factory;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::mutex registration_lock;
|
|
||||||
std::map<ProcessId, Registration> registrations;
|
|
||||||
|
|
||||||
std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
|
std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
|
||||||
std::unique_ptr<FileSys::BISFactory> bis_factory;
|
std::unique_ptr<FileSys::BISFactory> bis_factory;
|
||||||
|
|
||||||
|
@ -27,8 +27,6 @@
|
|||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
#include "core/hle/service/filesystem/filesystem.h"
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
#include "core/hle/service/filesystem/fsp_srv.h"
|
#include "core/hle/service/filesystem/fsp_srv.h"
|
||||||
#include "core/hle/service/filesystem/romfs_controller.h"
|
|
||||||
#include "core/hle/service/filesystem/save_data_controller.h"
|
|
||||||
#include "core/hle/service/hle_ipc.h"
|
#include "core/hle/service/hle_ipc.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/reporter.h"
|
#include "core/reporter.h"
|
||||||
@ -579,11 +577,9 @@ private:
|
|||||||
|
|
||||||
class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
|
class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
|
||||||
public:
|
public:
|
||||||
explicit ISaveDataInfoReader(Core::System& system_,
|
explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space,
|
||||||
std::shared_ptr<SaveDataController> save_data_controller_,
|
FileSystemController& fsc_)
|
||||||
FileSys::SaveDataSpaceId space)
|
: ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} {
|
||||||
: ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
|
|
||||||
save_data_controller_} {
|
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
|
{0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
|
||||||
};
|
};
|
||||||
@ -630,7 +626,7 @@ private:
|
|||||||
|
|
||||||
void FindAllSaves(FileSys::SaveDataSpaceId space) {
|
void FindAllSaves(FileSys::SaveDataSpaceId space) {
|
||||||
FileSys::VirtualDir save_root{};
|
FileSys::VirtualDir save_root{};
|
||||||
const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
|
const auto result = fsc.OpenSaveDataSpace(&save_root, space);
|
||||||
|
|
||||||
if (result != ResultSuccess || save_root == nullptr) {
|
if (result != ResultSuccess || save_root == nullptr) {
|
||||||
LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
|
LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
|
||||||
@ -727,8 +723,7 @@ private:
|
|||||||
};
|
};
|
||||||
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
|
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
|
||||||
|
|
||||||
ProcessId process_id = 0;
|
FileSystemController& fsc;
|
||||||
std::shared_ptr<SaveDataController> save_data_controller;
|
|
||||||
std::vector<SaveDataInfo> info;
|
std::vector<SaveDataInfo> info;
|
||||||
u64 next_entry_index = 0;
|
u64 next_entry_index = 0;
|
||||||
};
|
};
|
||||||
@ -868,20 +863,21 @@ FSP_SRV::FSP_SRV(Core::System& system_)
|
|||||||
if (Settings::values.enable_fs_access_log) {
|
if (Settings::values.enable_fs_access_log) {
|
||||||
access_log_mode = AccessLogMode::SdCard;
|
access_log_mode = AccessLogMode::SdCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should be true on creation
|
||||||
|
fsc.SetAutoSaveDataCreation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
FSP_SRV::~FSP_SRV() = default;
|
FSP_SRV::~FSP_SRV() = default;
|
||||||
|
|
||||||
void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
|
void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
|
||||||
current_process_id = ctx.GetPID();
|
IPC::RequestParser rp{ctx};
|
||||||
|
current_process_id = rp.Pop<u64>();
|
||||||
|
|
||||||
LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
|
LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
|
||||||
|
|
||||||
const auto res =
|
|
||||||
fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(res);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
|
void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
|
||||||
@ -920,8 +916,7 @@ void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
|
|||||||
uid[1], uid[0]);
|
uid[1], uid[0]);
|
||||||
|
|
||||||
FileSys::VirtualDir save_data_dir{};
|
FileSys::VirtualDir save_data_dir{};
|
||||||
save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser,
|
fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, save_struct);
|
||||||
save_struct);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@ -936,8 +931,7 @@ void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx)
|
|||||||
LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
|
LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
|
||||||
|
|
||||||
FileSys::VirtualDir save_data_dir{};
|
FileSys::VirtualDir save_data_dir{};
|
||||||
save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem,
|
fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, save_struct);
|
||||||
save_struct);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@ -956,8 +950,7 @@ void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
|
|||||||
LOG_INFO(Service_FS, "called.");
|
LOG_INFO(Service_FS, "called.");
|
||||||
|
|
||||||
FileSys::VirtualDir dir{};
|
FileSys::VirtualDir dir{};
|
||||||
auto result =
|
auto result = fsc.OpenSaveData(&dir, parameters.space_id, parameters.attribute);
|
||||||
save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
|
|
||||||
if (result != ResultSuccess) {
|
if (result != ResultSuccess) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
||||||
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
|
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
|
||||||
@ -1008,7 +1001,7 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
|
|||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<ISaveDataInfoReader>(
|
rb.PushIpcInterface<ISaveDataInfoReader>(
|
||||||
std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space));
|
std::make_shared<ISaveDataInfoReader>(system, space, fsc));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
|
void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
|
||||||
@ -1016,8 +1009,8 @@ void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller,
|
rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage,
|
||||||
FileSys::SaveDataSpaceId::TemporaryStorage);
|
fsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
|
void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
|
||||||
@ -1057,7 +1050,7 @@ void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
|
|||||||
LOG_DEBUG(Service_FS, "called");
|
LOG_DEBUG(Service_FS, "called");
|
||||||
|
|
||||||
if (!romfs) {
|
if (!romfs) {
|
||||||
auto current_romfs = romfs_controller->OpenRomFSCurrentProcess();
|
auto current_romfs = fsc.OpenRomFSCurrentProcess();
|
||||||
if (!current_romfs) {
|
if (!current_romfs) {
|
||||||
// TODO (bunnei): Find the right error code to use here
|
// TODO (bunnei): Find the right error code to use here
|
||||||
LOG_CRITICAL(Service_FS, "no file system interface available!");
|
LOG_CRITICAL(Service_FS, "no file system interface available!");
|
||||||
@ -1085,7 +1078,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
|
|||||||
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
|
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
|
||||||
storage_id, unknown, title_id);
|
storage_id, unknown, title_id);
|
||||||
|
|
||||||
auto data = romfs_controller->OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
|
auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
|
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
|
||||||
@ -1108,8 +1101,7 @@ void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
const FileSys::PatchManager pm{title_id, fsc, content_provider};
|
const FileSys::PatchManager pm{title_id, fsc, content_provider};
|
||||||
|
|
||||||
auto base =
|
auto base = fsc.OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||||
romfs_controller->OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data);
|
|
||||||
auto storage = std::make_shared<IStorage>(
|
auto storage = std::make_shared<IStorage>(
|
||||||
system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
|
system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
|
||||||
|
|
||||||
@ -1137,8 +1129,9 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
|
|||||||
|
|
||||||
LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
|
LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
|
||||||
|
|
||||||
auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex(
|
auto patched_romfs =
|
||||||
program_id, program_index, FileSys::ContentRecordType::Program);
|
fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index,
|
||||||
|
FileSys::ContentRecordType::Program);
|
||||||
|
|
||||||
if (!patched_romfs) {
|
if (!patched_romfs) {
|
||||||
// TODO: Find the right error code to use here
|
// TODO: Find the right error code to use here
|
||||||
@ -1159,7 +1152,7 @@ void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
|
|||||||
void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) {
|
void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_FS, "called");
|
LOG_DEBUG(Service_FS, "called");
|
||||||
|
|
||||||
save_data_controller->SetAutoCreate(false);
|
fsc.SetAutoSaveDataCreation(false);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -17,9 +17,6 @@ class FileSystemBackend;
|
|||||||
|
|
||||||
namespace Service::FileSystem {
|
namespace Service::FileSystem {
|
||||||
|
|
||||||
class RomFsController;
|
|
||||||
class SaveDataController;
|
|
||||||
|
|
||||||
enum class AccessLogVersion : u32 {
|
enum class AccessLogVersion : u32 {
|
||||||
V7_0_0 = 2,
|
V7_0_0 = 2,
|
||||||
|
|
||||||
@ -70,9 +67,6 @@ private:
|
|||||||
u64 current_process_id = 0;
|
u64 current_process_id = 0;
|
||||||
u32 access_log_program_index = 0;
|
u32 access_log_program_index = 0;
|
||||||
AccessLogMode access_log_mode = AccessLogMode::None;
|
AccessLogMode access_log_mode = AccessLogMode::None;
|
||||||
u64 program_id = 0;
|
|
||||||
std::shared_ptr<SaveDataController> save_data_controller;
|
|
||||||
std::shared_ptr<RomFsController> romfs_controller;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::FileSystem
|
} // namespace Service::FileSystem
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "core/hle/service/filesystem/romfs_controller.h"
|
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
|
||||||
|
|
||||||
RomFsController::RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_)
|
|
||||||
: factory{std::move(factory_)}, program_id{program_id_} {}
|
|
||||||
RomFsController::~RomFsController() = default;
|
|
||||||
|
|
||||||
FileSys::VirtualFile RomFsController::OpenRomFSCurrentProcess() {
|
|
||||||
return factory->OpenCurrentProcess(program_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSys::VirtualFile RomFsController::OpenPatchedRomFS(u64 title_id,
|
|
||||||
FileSys::ContentRecordType type) {
|
|
||||||
return factory->OpenPatchedRomFS(title_id, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSys::VirtualFile RomFsController::OpenPatchedRomFSWithProgramIndex(
|
|
||||||
u64 title_id, u8 program_index, FileSys::ContentRecordType type) {
|
|
||||||
return factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSys::VirtualFile RomFsController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
|
||||||
FileSys::ContentRecordType type) {
|
|
||||||
return factory->Open(title_id, storage_id, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<FileSys::NCA> RomFsController::OpenBaseNca(u64 title_id,
|
|
||||||
FileSys::StorageId storage_id,
|
|
||||||
FileSys::ContentRecordType type) {
|
|
||||||
return factory->GetEntry(title_id, storage_id, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::FileSystem
|
|
@ -1,31 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/file_sys/nca_metadata.h"
|
|
||||||
#include "core/file_sys/romfs_factory.h"
|
|
||||||
#include "core/file_sys/vfs_types.h"
|
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
|
||||||
|
|
||||||
class RomFsController {
|
|
||||||
public:
|
|
||||||
explicit RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_);
|
|
||||||
~RomFsController();
|
|
||||||
|
|
||||||
FileSys::VirtualFile OpenRomFSCurrentProcess();
|
|
||||||
FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type);
|
|
||||||
FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
|
|
||||||
FileSys::ContentRecordType type);
|
|
||||||
FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
|
||||||
FileSys::ContentRecordType type);
|
|
||||||
std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id,
|
|
||||||
FileSys::ContentRecordType type);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::shared_ptr<FileSys::RomFSFactory> factory;
|
|
||||||
const u64 program_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service::FileSystem
|
|
@ -1,99 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "core/core.h"
|
|
||||||
#include "core/file_sys/control_metadata.h"
|
|
||||||
#include "core/file_sys/errors.h"
|
|
||||||
#include "core/file_sys/patch_manager.h"
|
|
||||||
#include "core/hle/service/filesystem/save_data_controller.h"
|
|
||||||
#include "core/loader/loader.h"
|
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// A default size for normal/journal save data size if application control metadata cannot be found.
|
|
||||||
// This should be large enough to satisfy even the most extreme requirements (~4.2GB)
|
|
||||||
constexpr u64 SufficientSaveDataSize = 0xF0000000;
|
|
||||||
|
|
||||||
FileSys::SaveDataSize GetDefaultSaveDataSize(Core::System& system, u64 program_id) {
|
|
||||||
const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
|
|
||||||
system.GetContentProvider()};
|
|
||||||
const auto metadata = pm.GetControlMetadata();
|
|
||||||
const auto& nacp = metadata.first;
|
|
||||||
|
|
||||||
if (nacp != nullptr) {
|
|
||||||
return {nacp->GetDefaultNormalSaveSize(), nacp->GetDefaultJournalSaveSize()};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {SufficientSaveDataSize, SufficientSaveDataSize};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
SaveDataController::SaveDataController(Core::System& system_,
|
|
||||||
std::shared_ptr<FileSys::SaveDataFactory> factory_)
|
|
||||||
: system{system_}, factory{std::move(factory_)} {}
|
|
||||||
SaveDataController::~SaveDataController() = default;
|
|
||||||
|
|
||||||
Result SaveDataController::CreateSaveData(FileSys::VirtualDir* out_save_data,
|
|
||||||
FileSys::SaveDataSpaceId space,
|
|
||||||
const FileSys::SaveDataAttribute& attribute) {
|
|
||||||
LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
|
|
||||||
attribute.DebugInfo());
|
|
||||||
|
|
||||||
auto save_data = factory->Create(space, attribute);
|
|
||||||
if (save_data == nullptr) {
|
|
||||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_save_data = save_data;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SaveDataController::OpenSaveData(FileSys::VirtualDir* out_save_data,
|
|
||||||
FileSys::SaveDataSpaceId space,
|
|
||||||
const FileSys::SaveDataAttribute& attribute) {
|
|
||||||
auto save_data = factory->Open(space, attribute);
|
|
||||||
if (save_data == nullptr) {
|
|
||||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_save_data = save_data;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result SaveDataController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
|
|
||||||
FileSys::SaveDataSpaceId space) {
|
|
||||||
auto save_data_space = factory->GetSaveDataSpaceDirectory(space);
|
|
||||||
if (save_data_space == nullptr) {
|
|
||||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_save_data_space = save_data_space;
|
|
||||||
return ResultSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileSys::SaveDataSize SaveDataController::ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
|
|
||||||
u128 user_id) {
|
|
||||||
const auto value = factory->ReadSaveDataSize(type, title_id, user_id);
|
|
||||||
|
|
||||||
if (value.normal == 0 && value.journal == 0) {
|
|
||||||
const auto size = GetDefaultSaveDataSize(system, title_id);
|
|
||||||
factory->WriteSaveDataSize(type, title_id, user_id, size);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveDataController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
|
||||||
FileSys::SaveDataSize new_value) {
|
|
||||||
factory->WriteSaveDataSize(type, title_id, user_id, new_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveDataController::SetAutoCreate(bool state) {
|
|
||||||
factory->SetAutoCreate(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Service::FileSystem
|
|
@ -1,35 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/file_sys/nca_metadata.h"
|
|
||||||
#include "core/file_sys/savedata_factory.h"
|
|
||||||
#include "core/file_sys/vfs_types.h"
|
|
||||||
|
|
||||||
namespace Service::FileSystem {
|
|
||||||
|
|
||||||
class SaveDataController {
|
|
||||||
public:
|
|
||||||
explicit SaveDataController(Core::System& system,
|
|
||||||
std::shared_ptr<FileSys::SaveDataFactory> factory_);
|
|
||||||
~SaveDataController();
|
|
||||||
|
|
||||||
Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
|
|
||||||
const FileSys::SaveDataAttribute& attribute);
|
|
||||||
Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
|
|
||||||
const FileSys::SaveDataAttribute& attribute);
|
|
||||||
Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
|
|
||||||
FileSys::SaveDataSpaceId space);
|
|
||||||
|
|
||||||
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id);
|
|
||||||
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
|
||||||
FileSys::SaveDataSize new_value);
|
|
||||||
void SetAutoCreate(bool state);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Core::System& system;
|
|
||||||
const std::shared_ptr<FileSys::SaveDataFactory> factory;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Service::FileSystem
|
|
@ -1498,7 +1498,7 @@ void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
|
|||||||
bool check_device_index = false;
|
bool check_device_index = false;
|
||||||
|
|
||||||
switch (vibration_device_handle.npad_type) {
|
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::Handheld:
|
||||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||||
|
@ -223,8 +223,7 @@ Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64
|
|||||||
return VI::ResultNotFound;
|
return VI::ResultNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_vsync_event = display->GetVSyncEvent();
|
return display->GetVSyncEvent(out_vsync_event);
|
||||||
return ResultSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VI::Display* Nvnflinger::FindDisplay(u64 display_id) {
|
VI::Display* Nvnflinger::FindDisplay(u64 display_id) {
|
||||||
|
@ -256,13 +256,8 @@ Result ServerManager::WaitAndProcessImpl() {
|
|||||||
|
|
||||||
// Wait for a signal.
|
// Wait for a signal.
|
||||||
s32 out_index{-1};
|
s32 out_index{-1};
|
||||||
R_TRY_CATCH(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index,
|
R_TRY(Kernel::KSynchronizationObject::Wait(m_system.Kernel(), &out_index, wait_objs.data(),
|
||||||
wait_objs.data(), num_objs, -1)) {
|
num_objs, -1));
|
||||||
R_CATCH(Kernel::ResultSessionClosed) {
|
|
||||||
// On session closed, index is updated and we don't want to return an error.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
R_END_TRY_CATCH;
|
|
||||||
ASSERT(out_index >= 0 && out_index < num_objs);
|
ASSERT(out_index >= 0 && out_index < num_objs);
|
||||||
|
|
||||||
// Set the output index.
|
// Set the output index.
|
||||||
|
@ -71,7 +71,18 @@ size_t Display::GetNumLayers() const {
|
|||||||
return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); });
|
return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel::KReadableEvent* Display::GetVSyncEvent() {
|
Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) {
|
||||||
|
if (got_vsync_event) {
|
||||||
|
return ResultPermissionDenied;
|
||||||
|
}
|
||||||
|
|
||||||
|
got_vsync_event = true;
|
||||||
|
|
||||||
|
*out_vsync_event = GetVSyncEventUnchecked();
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() {
|
||||||
return &vsync_event->GetReadableEvent();
|
return &vsync_event->GetReadableEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,8 +74,16 @@ public:
|
|||||||
|
|
||||||
std::size_t GetNumLayers() const;
|
std::size_t GetNumLayers() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the internal vsync event.
|
||||||
|
*
|
||||||
|
* @returns The internal Vsync event if it has not yet been retrieved,
|
||||||
|
* VI::ResultPermissionDenied otherwise.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] Result GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event);
|
||||||
|
|
||||||
/// Gets the internal vsync event.
|
/// Gets the internal vsync event.
|
||||||
Kernel::KReadableEvent* GetVSyncEvent();
|
Kernel::KReadableEvent* GetVSyncEventUnchecked();
|
||||||
|
|
||||||
/// Signals the internal vsync event.
|
/// Signals the internal vsync event.
|
||||||
void SignalVSyncEvent();
|
void SignalVSyncEvent();
|
||||||
@ -96,6 +104,7 @@ public:
|
|||||||
/// Resets the display for a new connection.
|
/// Resets the display for a new connection.
|
||||||
void Reset() {
|
void Reset() {
|
||||||
layers.clear();
|
layers.clear();
|
||||||
|
got_vsync_event = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to find a layer with the given ID.
|
/// Attempts to find a layer with the given ID.
|
||||||
@ -124,6 +133,7 @@ private:
|
|||||||
|
|
||||||
std::vector<std::unique_ptr<Layer>> layers;
|
std::vector<std::unique_ptr<Layer>> layers;
|
||||||
Kernel::KEvent* vsync_event{};
|
Kernel::KEvent* vsync_event{};
|
||||||
|
bool got_vsync_event{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::VI
|
} // namespace Service::VI
|
||||||
|
@ -343,8 +343,8 @@ private:
|
|||||||
|
|
||||||
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
|
class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
|
||||||
public:
|
public:
|
||||||
explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
|
explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_)
|
||||||
: ServiceFramework{system_, "IManagerDisplayService"}, nvnflinger{nvnflinger_} {
|
: ServiceFramework{system_, "IManagerDisplayService"}, nv_flinger{nv_flinger_} {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{200, nullptr, "AllocateProcessHeapBlock"},
|
{200, nullptr, "AllocateProcessHeapBlock"},
|
||||||
@ -440,7 +440,7 @@ private:
|
|||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u64 display = rp.Pop<u64>();
|
const u64 display = rp.Pop<u64>();
|
||||||
|
|
||||||
const Result rc = nvnflinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown;
|
const Result rc = nv_flinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown;
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(rc);
|
rb.Push(rc);
|
||||||
@ -457,7 +457,7 @@ private:
|
|||||||
"(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
|
"(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
|
||||||
unknown, display, aruid);
|
unknown, display, aruid);
|
||||||
|
|
||||||
const auto layer_id = nvnflinger.CreateLayer(display);
|
const auto layer_id = nv_flinger.CreateLayer(display);
|
||||||
if (!layer_id) {
|
if (!layer_id) {
|
||||||
LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display);
|
LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@ -494,14 +494,14 @@ private:
|
|||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
Nvnflinger::Nvnflinger& nvnflinger;
|
Nvnflinger::Nvnflinger& nv_flinger;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
|
class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
|
||||||
public:
|
public:
|
||||||
IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_,
|
IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_,
|
||||||
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_)
|
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_)
|
||||||
: ServiceFramework{system_, "IApplicationDisplayService"}, nvnflinger{nvnflinger_},
|
: ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_},
|
||||||
hos_binder_driver_server{hos_binder_driver_server_} {
|
hos_binder_driver_server{hos_binder_driver_server_} {
|
||||||
|
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
@ -564,7 +564,7 @@ private:
|
|||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<ISystemDisplayService>(system, nvnflinger);
|
rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetManagerDisplayService(HLERequestContext& ctx) {
|
void GetManagerDisplayService(HLERequestContext& ctx) {
|
||||||
@ -572,7 +572,7 @@ private:
|
|||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<IManagerDisplayService>(system, nvnflinger);
|
rb.PushIpcInterface<IManagerDisplayService>(system, nv_flinger);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetIndirectDisplayTransactionService(HLERequestContext& ctx) {
|
void GetIndirectDisplayTransactionService(HLERequestContext& ctx) {
|
||||||
@ -607,7 +607,7 @@ private:
|
|||||||
|
|
||||||
ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
|
ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
|
||||||
|
|
||||||
const auto display_id = nvnflinger.OpenDisplay(name);
|
const auto display_id = nv_flinger.OpenDisplay(name);
|
||||||
if (!display_id) {
|
if (!display_id) {
|
||||||
LOG_ERROR(Service_VI, "Display not found! display_name={}", name);
|
LOG_ERROR(Service_VI, "Display not found! display_name={}", name);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@ -624,7 +624,7 @@ private:
|
|||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u64 display_id = rp.Pop<u64>();
|
const u64 display_id = rp.Pop<u64>();
|
||||||
|
|
||||||
const Result rc = nvnflinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown;
|
const Result rc = nv_flinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown;
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(rc);
|
rb.Push(rc);
|
||||||
@ -703,7 +703,7 @@ private:
|
|||||||
|
|
||||||
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
|
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
|
||||||
|
|
||||||
const auto display_id = nvnflinger.OpenDisplay(display_name);
|
const auto display_id = nv_flinger.OpenDisplay(display_name);
|
||||||
if (!display_id) {
|
if (!display_id) {
|
||||||
LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
|
LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@ -711,7 +711,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto buffer_queue_id = nvnflinger.FindBufferQueueId(*display_id, layer_id);
|
const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id);
|
||||||
if (!buffer_queue_id) {
|
if (!buffer_queue_id) {
|
||||||
LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
|
LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@ -719,7 +719,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvnflinger.OpenLayer(layer_id);
|
nv_flinger.OpenLayer(layer_id);
|
||||||
|
|
||||||
android::OutputParcel parcel;
|
android::OutputParcel parcel;
|
||||||
parcel.WriteInterface(NativeWindow{*buffer_queue_id});
|
parcel.WriteInterface(NativeWindow{*buffer_queue_id});
|
||||||
@ -737,7 +737,7 @@ private:
|
|||||||
|
|
||||||
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id);
|
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id);
|
||||||
|
|
||||||
nvnflinger.CloseLayer(layer_id);
|
nv_flinger.CloseLayer(layer_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@ -753,7 +753,7 @@ private:
|
|||||||
|
|
||||||
// TODO(Subv): What's the difference between a Stray and a Managed layer?
|
// TODO(Subv): What's the difference between a Stray and a Managed layer?
|
||||||
|
|
||||||
const auto layer_id = nvnflinger.CreateLayer(display_id);
|
const auto layer_id = nv_flinger.CreateLayer(display_id);
|
||||||
if (!layer_id) {
|
if (!layer_id) {
|
||||||
LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
|
LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@ -761,7 +761,7 @@ private:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id);
|
const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id);
|
||||||
if (!buffer_queue_id) {
|
if (!buffer_queue_id) {
|
||||||
LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
|
LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
@ -785,7 +785,7 @@ private:
|
|||||||
const u64 layer_id = rp.Pop<u64>();
|
const u64 layer_id = rp.Pop<u64>();
|
||||||
|
|
||||||
LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id);
|
LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id);
|
||||||
nvnflinger.DestroyLayer(layer_id);
|
nv_flinger.DestroyLayer(layer_id);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@ -798,7 +798,7 @@ private:
|
|||||||
LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
|
LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
|
||||||
|
|
||||||
Kernel::KReadableEvent* vsync_event{};
|
Kernel::KReadableEvent* vsync_event{};
|
||||||
const auto result = nvnflinger.FindVsyncEvent(&vsync_event, display_id);
|
const auto result = nv_flinger.FindVsyncEvent(&vsync_event, display_id);
|
||||||
if (result != ResultSuccess) {
|
if (result != ResultSuccess) {
|
||||||
if (result == ResultNotFound) {
|
if (result == ResultNotFound) {
|
||||||
LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
|
LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
|
||||||
@ -808,12 +808,6 @@ private:
|
|||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (vsync_event_fetched) {
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(VI::ResultPermissionDenied);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vsync_event_fetched = true;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
@ -905,9 +899,8 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Nvnflinger::Nvnflinger& nvnflinger;
|
Nvnflinger::Nvnflinger& nv_flinger;
|
||||||
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
|
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
|
||||||
bool vsync_event_fetched{false};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool IsValidServiceAccess(Permission permission, Policy policy) {
|
static bool IsValidServiceAccess(Permission permission, Policy policy) {
|
||||||
@ -923,7 +916,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
|
void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
|
||||||
Nvnflinger::Nvnflinger& nvnflinger,
|
Nvnflinger::Nvnflinger& nv_flinger,
|
||||||
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server,
|
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server,
|
||||||
Permission permission) {
|
Permission permission) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
@ -938,19 +931,19 @@ void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
|
|||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushIpcInterface<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server);
|
rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
|
void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger,
|
||||||
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) {
|
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) {
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
server_manager->RegisterNamedService(
|
server_manager->RegisterNamedService(
|
||||||
"vi:m", std::make_shared<VI_M>(system, nvnflinger, hos_binder_driver_server));
|
"vi:m", std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server));
|
||||||
server_manager->RegisterNamedService(
|
server_manager->RegisterNamedService(
|
||||||
"vi:s", std::make_shared<VI_S>(system, nvnflinger, hos_binder_driver_server));
|
"vi:s", std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server));
|
||||||
server_manager->RegisterNamedService(
|
server_manager->RegisterNamedService(
|
||||||
"vi:u", std::make_shared<VI_U>(system, nvnflinger, hos_binder_driver_server));
|
"vi:u", std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server));
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ void GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
|
|||||||
Permission permission);
|
Permission permission);
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
|
void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger,
|
||||||
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
|
Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
|
||||||
|
|
||||||
} // namespace Service::VI
|
} // namespace Service::VI
|
||||||
|
@ -216,6 +216,20 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
|||||||
LOG_DEBUG(Loader, "loaded module {} @ {:#X}", module, load_addr);
|
LOG_DEBUG(Loader, "loaded module {} @ {:#X}", module, load_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the RomFS by searching for a ".romfs" file in this directory
|
||||||
|
const auto& files = dir->GetFiles();
|
||||||
|
const auto romfs_iter =
|
||||||
|
std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& f) {
|
||||||
|
return f->GetName().find(".romfs") != std::string::npos;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register the RomFS if a ".romfs" file was found
|
||||||
|
if (romfs_iter != files.end() && *romfs_iter != nullptr) {
|
||||||
|
romfs = *romfs_iter;
|
||||||
|
system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(
|
||||||
|
*this, system.GetContentProvider(), system.GetFileSystemController()));
|
||||||
|
}
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
return {ResultStatus::Success,
|
return {ResultStatus::Success,
|
||||||
LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}};
|
LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}};
|
||||||
|
@ -74,10 +74,8 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S
|
|||||||
return load_result;
|
return load_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
system.GetFileSystemController().RegisterProcess(
|
system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(
|
||||||
process.GetProcessId(), nca->GetTitleId(),
|
*this, system.GetContentProvider(), system.GetFileSystemController()));
|
||||||
std::make_shared<FileSys::RomFSFactory>(*this, system.GetContentProvider(),
|
|
||||||
system.GetFileSystemController()));
|
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
return load_result;
|
return load_result;
|
||||||
|
@ -276,10 +276,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::KProcess& process, Core::S
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (romfs != nullptr) {
|
if (romfs != nullptr) {
|
||||||
system.GetFileSystemController().RegisterProcess(
|
system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(
|
||||||
process.GetProcessId(), {},
|
*this, system.GetContentProvider(), system.GetFileSystemController()));
|
||||||
std::make_unique<FileSys::RomFSFactory>(*this, system.GetContentProvider(),
|
|
||||||
system.GetFileSystemController()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
|
@ -111,8 +111,7 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
|
|||||||
|
|
||||||
FileSys::VirtualFile update_raw;
|
FileSys::VirtualFile update_raw;
|
||||||
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
|
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
|
||||||
system.GetFileSystemController().SetPackedUpdate(process.GetProcessId(),
|
system.GetFileSystemController().SetPackedUpdate(std::move(update_raw));
|
||||||
std::move(update_raw));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
|
@ -78,8 +78,7 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::KProcess& process, Core::S
|
|||||||
|
|
||||||
FileSys::VirtualFile update_raw;
|
FileSys::VirtualFile update_raw;
|
||||||
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
|
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
|
||||||
system.GetFileSystemController().SetPackedUpdate(process.GetProcessId(),
|
system.GetFileSystemController().SetPackedUpdate(std::move(update_raw));
|
||||||
std::move(update_raw));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is_loaded = true;
|
is_loaded = true;
|
||||||
|
@ -36,30 +36,6 @@ add_library(hid_core STATIC
|
|||||||
irsensor/processor_base.h
|
irsensor/processor_base.h
|
||||||
irsensor/tera_plugin_processor.cpp
|
irsensor/tera_plugin_processor.cpp
|
||||||
irsensor/tera_plugin_processor.h
|
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.cpp
|
||||||
resources/debug_pad/debug_pad.h
|
resources/debug_pad/debug_pad.h
|
||||||
resources/debug_pad/debug_pad_types.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.cpp
|
||||||
resources/npad/npad_resource.h
|
resources/npad/npad_resource.h
|
||||||
resources/npad/npad_types.h
|
resources/npad/npad_types.h
|
||||||
resources/npad/npad_vibration.cpp
|
|
||||||
resources/npad/npad_vibration.h
|
|
||||||
resources/palma/palma.cpp
|
resources/palma/palma.cpp
|
||||||
resources/palma/palma.h
|
resources/palma/palma.h
|
||||||
resources/six_axis/console_six_axis.cpp
|
resources/six_axis/console_six_axis.cpp
|
||||||
@ -104,14 +78,6 @@ add_library(hid_core STATIC
|
|||||||
resources/touch_screen/touch_types.h
|
resources/touch_screen/touch_types.h
|
||||||
resources/unique_pad/unique_pad.cpp
|
resources/unique_pad/unique_pad.cpp
|
||||||
resources/unique_pad/unique_pad.h
|
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.cpp
|
||||||
resources/applet_resource.h
|
resources/applet_resource.h
|
||||||
resources/controller_base.cpp
|
resources/controller_base.cpp
|
||||||
|
@ -27,7 +27,7 @@ EmulatedController::~EmulatedController() = default;
|
|||||||
NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) {
|
NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Settings::ControllerType::ProController:
|
case Settings::ControllerType::ProController:
|
||||||
return NpadStyleIndex::Fullkey;
|
return NpadStyleIndex::ProController;
|
||||||
case Settings::ControllerType::DualJoyconDetached:
|
case Settings::ControllerType::DualJoyconDetached:
|
||||||
return NpadStyleIndex::JoyconDual;
|
return NpadStyleIndex::JoyconDual;
|
||||||
case Settings::ControllerType::LeftJoycon:
|
case Settings::ControllerType::LeftJoycon:
|
||||||
@ -49,13 +49,13 @@ NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerTyp
|
|||||||
case Settings::ControllerType::SegaGenesis:
|
case Settings::ControllerType::SegaGenesis:
|
||||||
return NpadStyleIndex::SegaGenesis;
|
return NpadStyleIndex::SegaGenesis;
|
||||||
default:
|
default:
|
||||||
return NpadStyleIndex::Fullkey;
|
return NpadStyleIndex::ProController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) {
|
Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NpadStyleIndex::Fullkey:
|
case NpadStyleIndex::ProController:
|
||||||
return Settings::ControllerType::ProController;
|
return Settings::ControllerType::ProController;
|
||||||
case NpadStyleIndex::JoyconDual:
|
case NpadStyleIndex::JoyconDual:
|
||||||
return Settings::ControllerType::DualJoyconDetached;
|
return Settings::ControllerType::DualJoyconDetached;
|
||||||
@ -106,7 +106,7 @@ void EmulatedController::ReloadFromSettings() {
|
|||||||
SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
|
SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
|
||||||
original_npad_type = npad_type;
|
original_npad_type = npad_type;
|
||||||
} else {
|
} else {
|
||||||
SetNpadStyleIndex(NpadStyleIndex::Fullkey);
|
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
||||||
original_npad_type = npad_type;
|
original_npad_type = npad_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1073,7 +1073,7 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
|
|||||||
.body = GetNpadColor(controller.color_values[index].body),
|
.body = GetNpadColor(controller.color_values[index].body),
|
||||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||||
};
|
};
|
||||||
if (npad_type == NpadStyleIndex::Fullkey) {
|
if (npad_type == NpadStyleIndex::ProController) {
|
||||||
controller.colors_state.left = {
|
controller.colors_state.left = {
|
||||||
.body = GetNpadColor(controller.color_values[index].left_grip),
|
.body = GetNpadColor(controller.color_values[index].left_grip),
|
||||||
.button = GetNpadColor(controller.color_values[index].buttons),
|
.button = GetNpadColor(controller.color_values[index].buttons),
|
||||||
@ -1356,7 +1356,7 @@ bool EmulatedController::HasNfc() const {
|
|||||||
switch (npad_type) {
|
switch (npad_type) {
|
||||||
case NpadStyleIndex::JoyconRight:
|
case NpadStyleIndex::JoyconRight:
|
||||||
case NpadStyleIndex::JoyconDual:
|
case NpadStyleIndex::JoyconDual:
|
||||||
case NpadStyleIndex::Fullkey:
|
case NpadStyleIndex::ProController:
|
||||||
case NpadStyleIndex::Handheld:
|
case NpadStyleIndex::Handheld:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1548,7 +1548,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
|
|||||||
// Fallback Fullkey controllers to Pro controllers
|
// Fallback Fullkey controllers to Pro controllers
|
||||||
if (IsControllerFullkey() && supported_style_tag.fullkey) {
|
if (IsControllerFullkey() && supported_style_tag.fullkey) {
|
||||||
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
|
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
|
||||||
SetNpadStyleIndex(NpadStyleIndex::Fullkey);
|
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
||||||
Connect();
|
Connect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1556,13 +1556,13 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
|
|||||||
// Fallback Dual joycon controllers to Pro controllers
|
// Fallback Dual joycon controllers to Pro controllers
|
||||||
if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) {
|
if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) {
|
||||||
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
|
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
|
||||||
SetNpadStyleIndex(NpadStyleIndex::Fullkey);
|
SetNpadStyleIndex(NpadStyleIndex::ProController);
|
||||||
Connect();
|
Connect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback Pro controllers to Dual joycon
|
// 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);
|
LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type);
|
||||||
SetNpadStyleIndex(NpadStyleIndex::JoyconDual);
|
SetNpadStyleIndex(NpadStyleIndex::JoyconDual);
|
||||||
Connect();
|
Connect();
|
||||||
@ -1577,7 +1577,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
|
|||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NpadStyleIndex::Fullkey:
|
case NpadStyleIndex::ProController:
|
||||||
case NpadStyleIndex::GameCube:
|
case NpadStyleIndex::GameCube:
|
||||||
case NpadStyleIndex::NES:
|
case NpadStyleIndex::NES:
|
||||||
case NpadStyleIndex::SNES:
|
case NpadStyleIndex::SNES:
|
||||||
@ -1593,7 +1593,7 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
|
|||||||
std::scoped_lock lock{mutex};
|
std::scoped_lock lock{mutex};
|
||||||
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NpadStyleIndex::Fullkey:
|
case NpadStyleIndex::ProController:
|
||||||
return supported_style_tag.fullkey.As<bool>();
|
return supported_style_tag.fullkey.As<bool>();
|
||||||
case NpadStyleIndex::Handheld:
|
case NpadStyleIndex::Handheld:
|
||||||
return supported_style_tag.handheld.As<bool>();
|
return supported_style_tag.handheld.As<bool>();
|
||||||
|
@ -220,7 +220,6 @@ enum class NpadIdType : u32 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum class NpadInterfaceType : u8 {
|
enum class NpadInterfaceType : u8 {
|
||||||
None = 0,
|
|
||||||
Bluetooth = 1,
|
Bluetooth = 1,
|
||||||
Rail = 2,
|
Rail = 2,
|
||||||
Usb = 3,
|
Usb = 3,
|
||||||
@ -230,7 +229,7 @@ enum class NpadInterfaceType : u8 {
|
|||||||
// This is nn::hid::NpadStyleIndex
|
// This is nn::hid::NpadStyleIndex
|
||||||
enum class NpadStyleIndex : u8 {
|
enum class NpadStyleIndex : u8 {
|
||||||
None = 0,
|
None = 0,
|
||||||
Fullkey = 3,
|
ProController = 3,
|
||||||
Handheld = 4,
|
Handheld = 4,
|
||||||
HandheldNES = 4,
|
HandheldNES = 4,
|
||||||
JoyconDual = 5,
|
JoyconDual = 5,
|
||||||
|
@ -42,7 +42,7 @@ constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& hand
|
|||||||
|
|
||||||
constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) {
|
constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) {
|
||||||
switch (handle.npad_type) {
|
switch (handle.npad_type) {
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
case Core::HID::NpadStyleIndex::Handheld:
|
case Core::HID::NpadStyleIndex::Handheld:
|
||||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -193,7 +193,7 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) {
|
|||||||
case Core::HID::NpadStyleIndex::None:
|
case Core::HID::NpadStyleIndex::None:
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
break;
|
break;
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
|
shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
|
||||||
shared_memory->fullkey_color.fullkey = body_colors.fullkey;
|
shared_memory->fullkey_color.fullkey = body_colors.fullkey;
|
||||||
shared_memory->battery_level_dual = battery_level.dual.battery_level;
|
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:
|
case Core::HID::NpadStyleIndex::None:
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
break;
|
break;
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
case Core::HID::NpadStyleIndex::NES:
|
case Core::HID::NpadStyleIndex::NES:
|
||||||
case Core::HID::NpadStyleIndex::SNES:
|
case Core::HID::NpadStyleIndex::SNES:
|
||||||
case Core::HID::NpadStyleIndex::N64:
|
case Core::HID::NpadStyleIndex::N64:
|
||||||
@ -1292,7 +1292,7 @@ Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
|
|||||||
u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
|
u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
|
||||||
auto& controller = GetControllerFromHandle(aruid, sixaxis_handle);
|
auto& controller = GetControllerFromHandle(aruid, sixaxis_handle);
|
||||||
switch (sixaxis_handle.npad_type) {
|
switch (sixaxis_handle.npad_type) {
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
case Core::HID::NpadStyleIndex::Pokeball:
|
case Core::HID::NpadStyleIndex::Pokeball:
|
||||||
return controller.shared_memory->sixaxis_fullkey_properties;
|
return controller.shared_memory->sixaxis_fullkey_properties;
|
||||||
case Core::HID::NpadStyleIndex::Handheld:
|
case Core::HID::NpadStyleIndex::Handheld:
|
||||||
@ -1315,7 +1315,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
|
|||||||
u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
|
u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
|
||||||
const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle);
|
const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle);
|
||||||
switch (sixaxis_handle.npad_type) {
|
switch (sixaxis_handle.npad_type) {
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
case Core::HID::NpadStyleIndex::Pokeball:
|
case Core::HID::NpadStyleIndex::Pokeball:
|
||||||
return controller.shared_memory->sixaxis_fullkey_properties;
|
return controller.shared_memory->sixaxis_fullkey_properties;
|
||||||
case Core::HID::NpadStyleIndex::Handheld:
|
case Core::HID::NpadStyleIndex::Handheld:
|
||||||
|
@ -151,7 +151,7 @@ Core::HID::NpadStyleSet NPadData::GetSupportedNpadStyleSet() const {
|
|||||||
bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const {
|
bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const {
|
||||||
Core::HID::NpadStyleTag style = {supported_npad_style_set};
|
Core::HID::NpadStyleTag style = {supported_npad_style_set};
|
||||||
switch (style_index) {
|
switch (style_index) {
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
return style.fullkey.As<bool>();
|
return style.fullkey.As<bool>();
|
||||||
case Core::HID::NpadStyleIndex::Handheld:
|
case Core::HID::NpadStyleIndex::Handheld:
|
||||||
return style.handheld.As<bool>();
|
return style.handheld.As<bool>();
|
||||||
|
@ -252,103 +252,4 @@ enum class NpadLagerType : u32 {
|
|||||||
U,
|
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
|
} // namespace Service::HID
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -114,7 +114,7 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|||||||
case Core::HID::NpadStyleIndex::None:
|
case Core::HID::NpadStyleIndex::None:
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
break;
|
break;
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
|
set_motion_state(sixaxis_fullkey_state, motion_state[0]);
|
||||||
break;
|
break;
|
||||||
case Core::HID::NpadStyleIndex::Handheld:
|
case Core::HID::NpadStyleIndex::Handheld:
|
||||||
@ -345,7 +345,7 @@ SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
|
|||||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
|
const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
|
||||||
auto& controller = GetControllerFromHandle(sixaxis_handle);
|
auto& controller = GetControllerFromHandle(sixaxis_handle);
|
||||||
switch (sixaxis_handle.npad_type) {
|
switch (sixaxis_handle.npad_type) {
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
case Core::HID::NpadStyleIndex::Pokeball:
|
case Core::HID::NpadStyleIndex::Pokeball:
|
||||||
return controller.sixaxis_fullkey;
|
return controller.sixaxis_fullkey;
|
||||||
case Core::HID::NpadStyleIndex::Handheld:
|
case Core::HID::NpadStyleIndex::Handheld:
|
||||||
@ -368,7 +368,7 @@ const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
|
|||||||
const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
|
const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
|
||||||
const auto& controller = GetControllerFromHandle(sixaxis_handle);
|
const auto& controller = GetControllerFromHandle(sixaxis_handle);
|
||||||
switch (sixaxis_handle.npad_type) {
|
switch (sixaxis_handle.npad_type) {
|
||||||
case Core::HID::NpadStyleIndex::Fullkey:
|
case Core::HID::NpadStyleIndex::ProController:
|
||||||
case Core::HID::NpadStyleIndex::Pokeball:
|
case Core::HID::NpadStyleIndex::Pokeball:
|
||||||
return controller.sixaxis_fullkey;
|
return controller.sixaxis_fullkey;
|
||||||
case Core::HID::NpadStyleIndex::Handheld:
|
case Core::HID::NpadStyleIndex::Handheld:
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -65,14 +65,6 @@ void WriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value&
|
|||||||
WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32, sizeof(u32),
|
WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32, sizeof(u32),
|
||||||
&StorageDefinitions::U32, index_offset);
|
&StorageDefinitions::U32, index_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteStorageByCasLoop(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
||||||
Id value, Id bit_offset, Id bit_count) {
|
|
||||||
const Id pointer{StoragePointer(ctx, binding, offset, ctx.storage_types.U32, sizeof(u32),
|
|
||||||
&StorageDefinitions::U32)};
|
|
||||||
ctx.OpFunctionCall(ctx.TypeVoid(), ctx.write_storage_cas_loop_func, pointer, value, bit_offset,
|
|
||||||
bit_count);
|
|
||||||
}
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void EmitLoadGlobalU8(EmitContext&) {
|
void EmitLoadGlobalU8(EmitContext&) {
|
||||||
@ -227,42 +219,26 @@ Id EmitLoadStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Valu
|
|||||||
|
|
||||||
void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
Id value) {
|
Id value) {
|
||||||
if (ctx.profile.support_int8) {
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U8, value), ctx.storage_types.U8,
|
||||||
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U8, value), ctx.storage_types.U8,
|
sizeof(u8), &StorageDefinitions::U8);
|
||||||
sizeof(u8), &StorageDefinitions::U8);
|
|
||||||
} else {
|
|
||||||
WriteStorageByCasLoop(ctx, binding, offset, value, ctx.BitOffset8(offset), ctx.Const(8u));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
Id value) {
|
Id value) {
|
||||||
if (ctx.profile.support_int8) {
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S8, value), ctx.storage_types.S8,
|
||||||
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S8, value), ctx.storage_types.S8,
|
sizeof(s8), &StorageDefinitions::S8);
|
||||||
sizeof(s8), &StorageDefinitions::S8);
|
|
||||||
} else {
|
|
||||||
WriteStorageByCasLoop(ctx, binding, offset, value, ctx.BitOffset8(offset), ctx.Const(8u));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
Id value) {
|
Id value) {
|
||||||
if (ctx.profile.support_int16) {
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U16, value), ctx.storage_types.U16,
|
||||||
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U16, value), ctx.storage_types.U16,
|
sizeof(u16), &StorageDefinitions::U16);
|
||||||
sizeof(u16), &StorageDefinitions::U16);
|
|
||||||
} else {
|
|
||||||
WriteStorageByCasLoop(ctx, binding, offset, value, ctx.BitOffset16(offset), ctx.Const(16u));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
Id value) {
|
Id value) {
|
||||||
if (ctx.profile.support_int16) {
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S16, value), ctx.storage_types.S16,
|
||||||
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S16, value), ctx.storage_types.S16,
|
sizeof(s16), &StorageDefinitions::S16);
|
||||||
sizeof(s16), &StorageDefinitions::S16);
|
|
||||||
} else {
|
|
||||||
WriteStorageByCasLoop(ctx, binding, offset, value, ctx.BitOffset16(offset), ctx.Const(16u));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user