summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/scripts/format/script.sh39
-rw-r--r--.ci/scripts/linux/exec.sh2
-rw-r--r--.github/workflows/verify.yml8
-rw-r--r--LICENSES/BSD-2-Clause.txt2
-rw-r--r--LICENSES/BSD-3-Clause.txt2
-rw-r--r--LICENSES/MPL-2.0.txt2
-rw-r--r--externals/ffmpeg/CMakeLists.txt2
m---------externals/nx_tzdb/tzdb_to_nx0
-rw-r--r--src/android/app/build.gradle.kts83
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt33
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt98
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt105
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt36
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt88
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt57
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt101
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt36
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt192
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt28
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt72
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt36
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt50
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt45
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt76
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt27
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt129
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt9
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt18
-rw-r--r--src/android/app/src/main/jni/native.cpp4
-rw-r--r--src/android/app/src/main/res/layout-w600dp/fragment_about.xml4
-rw-r--r--src/android/app/src/main/res/layout/fragment_about.xml4
-rw-r--r--src/android/app/src/main/res/menu/menu_driver_manager.xml11
-rw-r--r--src/core/cpu_manager.h2
-rw-r--r--src/core/debugger/gdbstub.cpp44
-rw-r--r--src/core/frontend/applets/controller.cpp2
-rw-r--r--src/core/hle/kernel/k_memory_block.h14
-rw-r--r--src/core/hle/kernel/k_page_table_base.cpp12
-rw-r--r--src/core/hle/kernel/k_transfer_memory.cpp8
-rw-r--r--src/core/hle/kernel/svc/svc_transfer_memory.cpp4
-rw-r--r--src/core/hle/kernel/svc_types.h4
-rw-r--r--src/core/hle/service/am/applets/applet_profile_select.h2
-rw-r--r--src/core/hle/service/caps/caps_manager.cpp10
-rw-r--r--src/core/hle/service/caps/caps_manager.h4
-rw-r--r--src/core/hle/service/caps/caps_result.h2
-rw-r--r--src/core/hle/service/friend/friend.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp12
-rw-r--r--src/core/hle/service/hid/hid_server.cpp2
-rw-r--r--src/core/hle/service/hid/hidbus.cpp8
-rw-r--r--src/core/hle/service/hid/hidbus.h2
-rw-r--r--src/core/hle/service/hle_ipc.cpp20
-rw-r--r--src/core/hle/service/hle_ipc.h18
-rw-r--r--src/core/hle/service/nfc/common/amiibo_crypto.cpp10
-rw-r--r--src/core/hle/service/nfc/common/device.cpp6
-rw-r--r--src/core/hle/service/nfc/common/device.h2
-rw-r--r--src/core/hle/service/nfp/nfp_types.h14
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/nvdata.h2
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp3
-rw-r--r--src/core/hle/service/pcv/pcv.cpp10
-rw-r--r--src/core/hle/service/set/system_settings.cpp2
-rw-r--r--src/core/hle/service/set/system_settings.h4
-rw-r--r--src/core/hle/service/set/system_settings_server.cpp10
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp13
-rw-r--r--src/core/hle/service/vi/display/vi_display.h12
-rw-r--r--src/core/hle/service/vi/vi.cpp59
-rw-r--r--src/core/hle/service/vi/vi.h2
-rw-r--r--src/hid_core/CMakeLists.txt34
-rw-r--r--src/hid_core/frontend/emulated_controller.cpp22
-rw-r--r--src/hid_core/hid_types.h3
-rw-r--r--src/hid_core/hid_util.h2
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp197
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_battery_handler.h49
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp199
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_button_handler.h75
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp126
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h56
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp123
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_led_handler.h43
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp108
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h52
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp140
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h57
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_pad.cpp294
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_pad.h123
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp99
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_pad_holder.h47
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp47
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_palma_handler.h37
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp322
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_properties_handler.h86
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp154
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h61
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp73
-rw-r--r--src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h51
-rw-r--r--src/hid_core/resources/npad/npad.cpp8
-rw-r--r--src/hid_core/resources/npad/npad_data.cpp2
-rw-r--r--src/hid_core/resources/npad/npad_types.h99
-rw-r--r--src/hid_core/resources/npad/npad_vibration.cpp80
-rw-r--r--src/hid_core/resources/npad/npad_vibration.h34
-rw-r--r--src/hid_core/resources/six_axis/six_axis.cpp6
-rw-r--r--src/hid_core/resources/vibration/gc_vibration_device.cpp106
-rw-r--r--src/hid_core/resources/vibration/gc_vibration_device.h31
-rw-r--r--src/hid_core/resources/vibration/n64_vibration_device.cpp80
-rw-r--r--src/hid_core/resources/vibration/n64_vibration_device.h29
-rw-r--r--src/hid_core/resources/vibration/vibration_base.cpp30
-rw-r--r--src/hid_core/resources/vibration/vibration_base.h28
-rw-r--r--src/hid_core/resources/vibration/vibration_device.cpp84
-rw-r--r--src/hid_core/resources/vibration/vibration_device.h35
-rw-r--r--src/yuzu/applets/qt_controller.cpp8
-rw-r--r--src/yuzu/applets/qt_software_keyboard.cpp2
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp18
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp2
-rw-r--r--src/yuzu/main.cpp2
-rw-r--r--src/yuzu/util/controller_navigation.cpp4
118 files changed, 4212 insertions, 890 deletions
diff --git a/.ci/scripts/format/script.sh b/.ci/scripts/format/script.sh
index 25b0718f0..f9c63dbfa 100755
--- a/.ci/scripts/format/script.sh
+++ b/.ci/scripts/format/script.sh
@@ -3,38 +3,35 @@
3# SPDX-FileCopyrightText: 2019 yuzu Emulator Project 3# SPDX-FileCopyrightText: 2019 yuzu Emulator Project
4# SPDX-License-Identifier: GPL-2.0-or-later 4# SPDX-License-Identifier: GPL-2.0-or-later
5 5
6if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop \ 6shopt -s nullglob globstar
7 dist/*.svg dist/*.xml; then 7
8if git grep -nrI '\s$' src **/*.yml **/*.txt **/*.md Doxyfile .gitignore .gitmodules .ci* dist/*.desktop dist/*.svg dist/*.xml; then
8 echo Trailing whitespace found, aborting 9 echo Trailing whitespace found, aborting
9 exit 1 10 exit 1
10fi 11fi
11 12
12# Default clang-format points to default 3.5 version one 13# Default clang-format points to default 3.5 version one
13CLANG_FORMAT=${CLANG_FORMAT:-clang-format-15} 14CLANG_FORMAT="${CLANG_FORMAT:-clang-format-15}"
14$CLANG_FORMAT --version 15"$CLANG_FORMAT" --version
15
16if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
17 # Get list of every file modified in this pull request
18 files_to_lint="$(git diff --name-only --diff-filter=ACMRTUXB $TRAVIS_COMMIT_RANGE | grep '^src/[^.]*[.]\(cpp\|h\)$' || true)"
19else
20 # Check everything for branch pushes
21 files_to_lint="$(find src/ -name '*.cpp' -or -name '*.h')"
22fi
23 16
24# Turn off tracing for this because it's too verbose 17# Turn off tracing for this because it's too verbose
25set +x 18set +x
26 19
27for f in $files_to_lint; do 20# Check everything for branch pushes
28 d=$(diff -u "$f" <($CLANG_FORMAT "$f") || true) 21FILES_TO_LINT="$(find src/ -name '*.cpp' -or -name '*.h')"
29 if ! [ -z "$d" ]; then 22
30 echo "!!! $f not compliant to coding style, here is the fix:" 23for f in $FILES_TO_LINT; do
31 echo "$d" 24 echo "$f"
32 fail=1 25 "$CLANG_FORMAT" -i "$f"
33 fi
34done 26done
35 27
36set -x 28DIFF=$(git -c core.fileMode=false diff)
37 29
38if [ "$fail" = 1 ]; then 30if [ ! -z "$DIFF" ]; then
31 echo "!!! Not compliant to coding style, here is the fix:"
32 echo "$DIFF"
39 exit 1 33 exit 1
40fi 34fi
35
36cd src/android
37./gradlew ktlintCheck
diff --git a/.ci/scripts/linux/exec.sh b/.ci/scripts/linux/exec.sh
index fa3d78cc2..04e2486a1 100644
--- a/.ci/scripts/linux/exec.sh
+++ b/.ci/scripts/linux/exec.sh
@@ -9,7 +9,7 @@ chmod a+x ./.ci/scripts/linux/docker.sh
9sudo chown -R 1027 ./ 9sudo chown -R 1027 ./
10 10
11# The environment variables listed below: 11# The environment variables listed below:
12# AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION 12# AZURECIREPO TITLEBARFORMATIDLE TITLEBARFORMATRUNNING DISPLAYVERSION
13# are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps 13# are requested in src/common/CMakeLists.txt and appear to be provided somewhere in Azure DevOps
14 14
15docker 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" 15docker 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"
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index c073f3f3f..62eb69aeb 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -13,13 +13,15 @@ jobs:
13 format: 13 format:
14 name: 'verify format' 14 name: 'verify format'
15 runs-on: ubuntu-latest 15 runs-on: ubuntu-latest
16 container:
17 image: yuzuemu/build-environments:linux-clang-format
18 options: -u 1001
19 steps: 16 steps:
20 - uses: actions/checkout@v3 17 - uses: actions/checkout@v3
21 with: 18 with:
22 submodules: false 19 submodules: false
20 - name: set up JDK 17
21 uses: actions/setup-java@v3
22 with:
23 java-version: '17'
24 distribution: 'temurin'
23 - name: 'Verify Formatting' 25 - name: 'Verify Formatting'
24 run: bash -ex ./.ci/scripts/format/script.sh 26 run: bash -ex ./.ci/scripts/format/script.sh
25 build: 27 build:
diff --git a/LICENSES/BSD-2-Clause.txt b/LICENSES/BSD-2-Clause.txt
index 5f662b354..eb3c575b8 100644
--- a/LICENSES/BSD-2-Clause.txt
+++ b/LICENSES/BSD-2-Clause.txt
@@ -1,4 +1,4 @@
1Copyright (c) <year> <owner> 1Copyright (c) <year> <owner>
2 2
3Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 3Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 4
diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt
index ea890afbc..086d3992c 100644
--- a/LICENSES/BSD-3-Clause.txt
+++ b/LICENSES/BSD-3-Clause.txt
@@ -1,4 +1,4 @@
1Copyright (c) <year> <owner>. 1Copyright (c) <year> <owner>.
2 2
3Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 3Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 4
diff --git a/LICENSES/MPL-2.0.txt b/LICENSES/MPL-2.0.txt
index 14e2f777f..a612ad981 100644
--- a/LICENSES/MPL-2.0.txt
+++ b/LICENSES/MPL-2.0.txt
@@ -35,7 +35,7 @@ Mozilla Public License Version 2.0
35 means any form of the work other than Source Code Form. 35 means any form of the work other than Source Code Form.
36 36
371.7. "Larger Work" 371.7. "Larger Work"
38 means a work that combines Covered Software with other material, in 38 means a work that combines Covered Software with other material, in
39 a separate file or files, that is not Covered Software. 39 a separate file or files, that is not Covered Software.
40 40
411.8. "License" 411.8. "License"
diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt
index f2886eb6c..543585d4f 100644
--- a/externals/ffmpeg/CMakeLists.txt
+++ b/externals/ffmpeg/CMakeLists.txt
@@ -138,7 +138,7 @@ if (NOT WIN32 AND NOT ANDROID)
138 --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android- 138 --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
139 --sysroot=${SYSROOT} 139 --sysroot=${SYSROOT}
140 --target-os=android 140 --target-os=android
141 --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" 141 --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
142 --extra-ldflags="-nostdlib" 142 --extra-ldflags="-nostdlib"
143 ) 143 )
144 endif() 144 endif()
diff --git a/externals/nx_tzdb/tzdb_to_nx b/externals/nx_tzdb/tzdb_to_nx
Subproject f6680093bca30265c161581fd813d4ddd33f1e3 Subproject 404d39004570a26c734a9d1fa29ab4d63089c59
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts
index 53aafa08c..06e59d1ac 100644
--- a/src/android/app/build.gradle.kts
+++ b/src/android/app/build.gradle.kts
@@ -188,8 +188,15 @@ tasks.create<Delete>("ktlintReset") {
188 delete(File(buildDir.path + File.separator + "intermediates/ktLint")) 188 delete(File(buildDir.path + File.separator + "intermediates/ktLint"))
189} 189}
190 190
191val showFormatHelp = {
192 logger.lifecycle(
193 "If this check fails, please try running \"gradlew ktlintFormat\" for automatic " +
194 "codestyle fixes"
195 )
196}
197tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() }
198tasks.getByPath("ktlintMainSourceSetCheck").doFirst { showFormatHelp.invoke() }
191tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset") 199tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset")
192tasks.getByPath("preBuild").dependsOn("ktlintCheck")
193 200
194ktlint { 201ktlint {
195 version.set("0.47.1") 202 version.set("0.47.1")
@@ -228,71 +235,33 @@ dependencies {
228 implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") 235 implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
229} 236}
230 237
231fun getGitVersion(): String { 238fun runGitCommand(command: List<String>): String {
232 var versionName = "0.0" 239 return try {
233 240 ProcessBuilder(command)
234 try {
235 versionName = ProcessBuilder("git", "describe", "--always", "--long")
236 .directory(project.rootDir) 241 .directory(project.rootDir)
237 .redirectOutput(ProcessBuilder.Redirect.PIPE) 242 .redirectOutput(ProcessBuilder.Redirect.PIPE)
238 .redirectError(ProcessBuilder.Redirect.PIPE) 243 .redirectError(ProcessBuilder.Redirect.PIPE)
239 .start().inputStream.bufferedReader().use { it.readText() } 244 .start().inputStream.bufferedReader().use { it.readText() }
240 .trim() 245 .trim()
241 .replace(Regex("(-0)?-[^-]+$"), "")
242 } catch (e: Exception) { 246 } catch (e: Exception) {
243 logger.error("Cannot find git, defaulting to dummy version number") 247 logger.error("Cannot find git")
248 ""
244 } 249 }
245
246 if (System.getenv("GITHUB_ACTIONS") != null) {
247 val gitTag = System.getenv("GIT_TAG_NAME")
248 versionName = gitTag ?: versionName
249 }
250
251 return versionName
252} 250}
253 251
254fun getGitHash(): String { 252fun getGitVersion(): String {
255 try { 253 val versionName = if (System.getenv("GITHUB_ACTIONS") != null) {
256 val processBuilder = ProcessBuilder("git", "rev-parse", "--short", "HEAD") 254 val gitTag = System.getenv("GIT_TAG_NAME") ?: ""
257 processBuilder.directory(project.rootDir) 255 gitTag
258 val process = processBuilder.start() 256 } else {
259 val inputStream = process.inputStream 257 runGitCommand(listOf("git", "describe", "--always", "--long"))
260 val errorStream = process.errorStream 258 .replace(Regex("(-0)?-[^-]+$"), "")
261 process.waitFor()
262
263 return if (process.exitValue() == 0) {
264 inputStream.bufferedReader()
265 .use { it.readText().trim() } // return the value of gitHash
266 } else {
267 val errorMessage = errorStream.bufferedReader().use { it.readText().trim() }
268 logger.error("Error running git command: $errorMessage")
269 "dummy-hash" // return a dummy hash value in case of an error
270 }
271 } catch (e: Exception) {
272 logger.error("$e: Cannot find git, defaulting to dummy build hash")
273 return "dummy-hash" // return a dummy hash value in case of an error
274 } 259 }
260 return versionName.ifEmpty { "0.0" }
275} 261}
276 262
277fun getBranch(): String { 263fun getGitHash(): String =
278 try { 264 runGitCommand(listOf("git", "rev-parse", "--short", "HEAD")).ifEmpty { "dummy-hash" }
279 val processBuilder = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD") 265
280 processBuilder.directory(project.rootDir) 266fun getBranch(): String =
281 val process = processBuilder.start() 267 runGitCommand(listOf("git", "rev-parse", "--abbrev-ref", "HEAD")).ifEmpty { "dummy-hash" }
282 val inputStream = process.inputStream
283 val errorStream = process.errorStream
284 process.waitFor()
285
286 return if (process.exitValue() == 0) {
287 inputStream.bufferedReader()
288 .use { it.readText().trim() } // return the value of gitHash
289 } else {
290 val errorMessage = errorStream.bufferedReader().use { it.readText().trim() }
291 logger.error("Error running git command: $errorMessage")
292 "dummy-hash" // return a dummy hash value in case of an error
293 }
294 } catch (e: Exception) {
295 logger.error("$e: Cannot find git, defaulting to dummy build hash")
296 return "dummy-hash" // return a dummy hash value in case of an error
297 }
298}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt
new file mode 100644
index 000000000..f006f9e3d
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractDiffAdapter.kt
@@ -0,0 +1,33 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.adapters
5
6import android.annotation.SuppressLint
7import androidx.recyclerview.widget.AsyncDifferConfig
8import androidx.recyclerview.widget.DiffUtil
9import androidx.recyclerview.widget.ListAdapter
10import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
11import androidx.recyclerview.widget.RecyclerView
12
13/**
14 * Generic adapter that implements an [AsyncDifferConfig] and covers some of the basic boilerplate
15 * code used in every [RecyclerView].
16 * Type assigned to [Model] must inherit from [Object] in order to be compared properly.
17 */
18abstract class AbstractDiffAdapter<Model : Any, Holder : AbstractViewHolder<Model>> :
19 ListAdapter<Model, Holder>(AsyncDifferConfig.Builder(DiffCallback<Model>()).build()) {
20 override fun onBindViewHolder(holder: Holder, position: Int) =
21 holder.bind(currentList[position])
22
23 private class DiffCallback<Model> : DiffUtil.ItemCallback<Model>() {
24 override fun areItemsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean {
25 return oldItem === newItem
26 }
27
28 @SuppressLint("DiffUtilEquals")
29 override fun areContentsTheSame(oldItem: Model & Any, newItem: Model & Any): Boolean {
30 return oldItem == newItem
31 }
32 }
33}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt
new file mode 100644
index 000000000..3dfee3d0c
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractListAdapter.kt
@@ -0,0 +1,98 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.adapters
5
6import android.annotation.SuppressLint
7import androidx.recyclerview.widget.RecyclerView
8import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
9
10/**
11 * Generic list class meant to take care of basic lists
12 * @param currentList The list to show initially
13 */
14abstract class AbstractListAdapter<Model : Any, Holder : AbstractViewHolder<Model>>(
15 open var currentList: List<Model>
16) : RecyclerView.Adapter<Holder>() {
17 override fun onBindViewHolder(holder: Holder, position: Int) =
18 holder.bind(currentList[position])
19
20 override fun getItemCount(): Int = currentList.size
21
22 /**
23 * Adds an item to [currentList] and notifies the underlying adapter of the change. If no parameter
24 * is passed in for position, [item] is added to the end of the list. Invokes [callback] last.
25 * @param item The item to add to the list
26 * @param position Index where [item] will be added
27 * @param callback Lambda that's called at the end of the list changes and has the added list
28 * position passed in as a parameter
29 */
30 open fun addItem(item: Model, position: Int = -1, callback: ((position: Int) -> Unit)? = null) {
31 val newList = currentList.toMutableList()
32 val positionToUpdate: Int
33 if (position == -1) {
34 newList.add(item)
35 currentList = newList
36 positionToUpdate = currentList.size - 1
37 } else {
38 newList.add(position, item)
39 currentList = newList
40 positionToUpdate = position
41 }
42 onItemAdded(positionToUpdate, callback)
43 }
44
45 protected fun onItemAdded(position: Int, callback: ((Int) -> Unit)? = null) {
46 notifyItemInserted(position)
47 callback?.invoke(position)
48 }
49
50 /**
51 * Replaces the [item] at [position] in the [currentList] and notifies the underlying adapter
52 * of the change. Invokes [callback] last.
53 * @param item New list item
54 * @param position Index where [item] will replace the existing list item
55 * @param callback Lambda that's called at the end of the list changes and has the changed list
56 * position passed in as a parameter
57 */
58 fun changeItem(item: Model, position: Int, callback: ((position: Int) -> Unit)? = null) {
59 val newList = currentList.toMutableList()
60 newList[position] = item
61 currentList = newList
62 onItemChanged(position, callback)
63 }
64
65 protected fun onItemChanged(position: Int, callback: ((Int) -> Unit)? = null) {
66 notifyItemChanged(position)
67 callback?.invoke(position)
68 }
69
70 /**
71 * Removes the list item at [position] in [currentList] and notifies the underlying adapter
72 * of the change. Invokes [callback] last.
73 * @param position Index where the list item will be removed
74 * @param callback Lambda that's called at the end of the list changes and has the removed list
75 * position passed in as a parameter
76 */
77 fun removeItem(position: Int, callback: ((position: Int) -> Unit)? = null) {
78 val newList = currentList.toMutableList()
79 newList.removeAt(position)
80 currentList = newList
81 onItemRemoved(position, callback)
82 }
83
84 protected fun onItemRemoved(position: Int, callback: ((Int) -> Unit)? = null) {
85 notifyItemRemoved(position)
86 callback?.invoke(position)
87 }
88
89 /**
90 * Replaces [currentList] with [newList] and notifies the underlying adapter of the change.
91 * @param newList The new list to replace [currentList]
92 */
93 @SuppressLint("NotifyDataSetChanged")
94 open fun replaceList(newList: List<Model>) {
95 currentList = newList
96 notifyDataSetChanged()
97 }
98}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt
new file mode 100644
index 000000000..52163f9d7
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AbstractSingleSelectionList.kt
@@ -0,0 +1,105 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.adapters
5
6import org.yuzu.yuzu_emu.model.SelectableItem
7import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
8
9/**
10 * Generic list class meant to take care of single selection UI updates
11 * @param currentList The list to show initially
12 * @param defaultSelection The default selection to use if no list items are selected by
13 * [SelectableItem.selected] or if the currently selected item is removed from the list
14 */
15abstract class AbstractSingleSelectionList<
16 Model : SelectableItem,
17 Holder : AbstractViewHolder<Model>
18 >(
19 final override var currentList: List<Model>,
20 private val defaultSelection: DefaultSelection = DefaultSelection.Start
21) : AbstractListAdapter<Model, Holder>(currentList) {
22 var selectedItem = getDefaultSelection()
23
24 init {
25 findSelectedItem()
26 }
27
28 /**
29 * Changes the selection state of the [SelectableItem] that was selected and the previously selected
30 * item and notifies the underlying adapter of the change for those items. Invokes [callback] last.
31 * Does nothing if [position] is the same as the currently selected item.
32 * @param position Index of the item that was selected
33 * @param callback Lambda that's called at the end of the list changes and has the selected list
34 * position passed in as a parameter
35 */
36 fun selectItem(position: Int, callback: ((position: Int) -> Unit)? = null) {
37 if (position == selectedItem) {
38 return
39 }
40
41 val previouslySelectedItem = selectedItem
42 selectedItem = position
43 if (currentList.indices.contains(selectedItem)) {
44 currentList[selectedItem].onSelectionStateChanged(true)
45 }
46 if (currentList.indices.contains(previouslySelectedItem)) {
47 currentList[previouslySelectedItem].onSelectionStateChanged(false)
48 }
49 onItemChanged(previouslySelectedItem)
50 onItemChanged(selectedItem)
51 callback?.invoke(position)
52 }
53
54 /**
55 * Removes a given item from the list and notifies the underlying adapter of the change. If the
56 * currently selected item was the item that was removed, the item at the position provided
57 * by [defaultSelection] will be made the new selection. Invokes [callback] last.
58 * @param position Index of the item that was removed
59 * @param callback Lambda that's called at the end of the list changes and has the removed and
60 * selected list positions passed in as parameters
61 */
62 fun removeSelectableItem(
63 position: Int,
64 callback: ((removedPosition: Int, selectedPosition: Int) -> Unit)?
65 ) {
66 removeItem(position)
67 if (position == selectedItem) {
68 selectedItem = getDefaultSelection()
69 currentList[selectedItem].onSelectionStateChanged(true)
70 onItemChanged(selectedItem)
71 } else if (position < selectedItem) {
72 selectedItem--
73 }
74 callback?.invoke(position, selectedItem)
75 }
76
77 override fun addItem(item: Model, position: Int, callback: ((Int) -> Unit)?) {
78 super.addItem(item, position, callback)
79 if (position <= selectedItem && position != -1) {
80 selectedItem++
81 }
82 }
83
84 override fun replaceList(newList: List<Model>) {
85 super.replaceList(newList)
86 findSelectedItem()
87 }
88
89 private fun findSelectedItem() {
90 for (i in currentList.indices) {
91 if (currentList[i].selected) {
92 selectedItem = i
93 break
94 }
95 }
96 }
97
98 private fun getDefaultSelection(): Int =
99 when (defaultSelection) {
100 DefaultSelection.Start -> currentList.indices.first
101 DefaultSelection.End -> currentList.indices.last
102 }
103
104 enum class DefaultSelection { Start, End }
105}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt
index 15c7ca3c9..94c151325 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AddonAdapter.kt
@@ -5,48 +5,28 @@ package org.yuzu.yuzu_emu.adapters
5 5
6import android.view.LayoutInflater 6import android.view.LayoutInflater
7import android.view.ViewGroup 7import android.view.ViewGroup
8import androidx.recyclerview.widget.AsyncDifferConfig
9import androidx.recyclerview.widget.DiffUtil
10import androidx.recyclerview.widget.ListAdapter
11import androidx.recyclerview.widget.RecyclerView
12import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding 8import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding
13import org.yuzu.yuzu_emu.model.Addon 9import org.yuzu.yuzu_emu.model.Addon
10import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
14 11
15class AddonAdapter : ListAdapter<Addon, AddonAdapter.AddonViewHolder>( 12class AddonAdapter : AbstractDiffAdapter<Addon, AddonAdapter.AddonViewHolder>() {
16 AsyncDifferConfig.Builder(DiffCallback()).build()
17) {
18 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder { 13 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddonViewHolder {
19 ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false) 14 ListItemAddonBinding.inflate(LayoutInflater.from(parent.context), parent, false)
20 .also { return AddonViewHolder(it) } 15 .also { return AddonViewHolder(it) }
21 } 16 }
22 17
23 override fun getItemCount(): Int = currentList.size
24
25 override fun onBindViewHolder(holder: AddonViewHolder, position: Int) =
26 holder.bind(currentList[position])
27
28 inner class AddonViewHolder(val binding: ListItemAddonBinding) : 18 inner class AddonViewHolder(val binding: ListItemAddonBinding) :
29 RecyclerView.ViewHolder(binding.root) { 19 AbstractViewHolder<Addon>(binding) {
30 fun bind(addon: Addon) { 20 override fun bind(model: Addon) {
31 binding.root.setOnClickListener { 21 binding.root.setOnClickListener {
32 binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked 22 binding.addonSwitch.isChecked = !binding.addonSwitch.isChecked
33 } 23 }
34 binding.title.text = addon.title 24 binding.title.text = model.title
35 binding.version.text = addon.version 25 binding.version.text = model.version
36 binding.addonSwitch.setOnCheckedChangeListener { _, checked -> 26 binding.addonSwitch.setOnCheckedChangeListener { _, checked ->
37 addon.enabled = checked 27 model.enabled = checked
38 } 28 }
39 binding.addonSwitch.isChecked = addon.enabled 29 binding.addonSwitch.isChecked = model.enabled
40 }
41 }
42
43 private class DiffCallback : DiffUtil.ItemCallback<Addon>() {
44 override fun areItemsTheSame(oldItem: Addon, newItem: Addon): Boolean {
45 return oldItem == newItem
46 }
47
48 override fun areContentsTheSame(oldItem: Addon, newItem: Addon): Boolean {
49 return oldItem == newItem
50 } 30 }
51 } 31 }
52} 32}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt
index 4a05c5be9..41d7f72b8 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/AppletAdapter.kt
@@ -4,13 +4,11 @@
4package org.yuzu.yuzu_emu.adapters 4package org.yuzu.yuzu_emu.adapters
5 5
6import android.view.LayoutInflater 6import android.view.LayoutInflater
7import android.view.View
8import android.view.ViewGroup 7import android.view.ViewGroup
9import android.widget.Toast 8import android.widget.Toast
10import androidx.core.content.res.ResourcesCompat 9import androidx.core.content.res.ResourcesCompat
11import androidx.fragment.app.FragmentActivity 10import androidx.fragment.app.FragmentActivity
12import androidx.navigation.findNavController 11import androidx.navigation.findNavController
13import androidx.recyclerview.widget.RecyclerView
14import org.yuzu.yuzu_emu.HomeNavigationDirections 12import org.yuzu.yuzu_emu.HomeNavigationDirections
15import org.yuzu.yuzu_emu.NativeLibrary 13import org.yuzu.yuzu_emu.NativeLibrary
16import org.yuzu.yuzu_emu.R 14import org.yuzu.yuzu_emu.R
@@ -19,72 +17,58 @@ import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
19import org.yuzu.yuzu_emu.model.Applet 17import org.yuzu.yuzu_emu.model.Applet
20import org.yuzu.yuzu_emu.model.AppletInfo 18import org.yuzu.yuzu_emu.model.AppletInfo
21import org.yuzu.yuzu_emu.model.Game 19import org.yuzu.yuzu_emu.model.Game
20import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
22 21
23class AppletAdapter(val activity: FragmentActivity, var applets: List<Applet>) : 22class AppletAdapter(val activity: FragmentActivity, applets: List<Applet>) :
24 RecyclerView.Adapter<AppletAdapter.AppletViewHolder>(), 23 AbstractListAdapter<Applet, AppletAdapter.AppletViewHolder>(applets) {
25 View.OnClickListener {
26
27 override fun onCreateViewHolder( 24 override fun onCreateViewHolder(
28 parent: ViewGroup, 25 parent: ViewGroup,
29 viewType: Int 26 viewType: Int
30 ): AppletAdapter.AppletViewHolder { 27 ): AppletAdapter.AppletViewHolder {
31 CardSimpleOutlinedBinding.inflate(LayoutInflater.from(parent.context), parent, false) 28 CardSimpleOutlinedBinding.inflate(LayoutInflater.from(parent.context), parent, false)
32 .apply { root.setOnClickListener(this@AppletAdapter) }
33 .also { return AppletViewHolder(it) } 29 .also { return AppletViewHolder(it) }
34 } 30 }
35 31
36 override fun onBindViewHolder(holder: AppletViewHolder, position: Int) =
37 holder.bind(applets[position])
38
39 override fun getItemCount(): Int = applets.size
40
41 override fun onClick(view: View) {
42 val applet = (view.tag as AppletViewHolder).applet
43 val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId)
44 if (appletPath.isEmpty()) {
45 Toast.makeText(
46 YuzuApplication.appContext,
47 R.string.applets_error_applet,
48 Toast.LENGTH_SHORT
49 ).show()
50 return
51 }
52
53 if (applet.appletInfo == AppletInfo.Cabinet) {
54 view.findNavController()
55 .navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment)
56 return
57 }
58
59 NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId)
60 val appletGame = Game(
61 title = YuzuApplication.appContext.getString(applet.titleId),
62 path = appletPath
63 )
64 val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
65 view.findNavController().navigate(action)
66 }
67
68 inner class AppletViewHolder(val binding: CardSimpleOutlinedBinding) : 32 inner class AppletViewHolder(val binding: CardSimpleOutlinedBinding) :
69 RecyclerView.ViewHolder(binding.root) { 33 AbstractViewHolder<Applet>(binding) {
70 lateinit var applet: Applet 34 override fun bind(model: Applet) {
71 35 binding.title.setText(model.titleId)
72 init { 36 binding.description.setText(model.descriptionId)
73 itemView.tag = this
74 }
75
76 fun bind(applet: Applet) {
77 this.applet = applet
78
79 binding.title.setText(applet.titleId)
80 binding.description.setText(applet.descriptionId)
81 binding.icon.setImageDrawable( 37 binding.icon.setImageDrawable(
82 ResourcesCompat.getDrawable( 38 ResourcesCompat.getDrawable(
83 binding.icon.context.resources, 39 binding.icon.context.resources,
84 applet.iconId, 40 model.iconId,
85 binding.icon.context.theme 41 binding.icon.context.theme
86 ) 42 )
87 ) 43 )
44
45 binding.root.setOnClickListener { onClick(model) }
46 }
47
48 fun onClick(applet: Applet) {
49 val appletPath = NativeLibrary.getAppletLaunchPath(applet.appletInfo.entryId)
50 if (appletPath.isEmpty()) {
51 Toast.makeText(
52 binding.root.context,
53 R.string.applets_error_applet,
54 Toast.LENGTH_SHORT
55 ).show()
56 return
57 }
58
59 if (applet.appletInfo == AppletInfo.Cabinet) {
60 binding.root.findNavController()
61 .navigate(R.id.action_appletLauncherFragment_to_cabinetLauncherDialogFragment)
62 return
63 }
64
65 NativeLibrary.setCurrentAppletId(applet.appletInfo.appletId)
66 val appletGame = Game(
67 title = YuzuApplication.appContext.getString(applet.titleId),
68 path = appletPath
69 )
70 val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
71 binding.root.findNavController().navigate(action)
88 } 72 }
89 } 73 }
90} 74}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt
index e7b7c0f2f..a56137148 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/CabinetLauncherDialogAdapter.kt
@@ -4,12 +4,10 @@
4package org.yuzu.yuzu_emu.adapters 4package org.yuzu.yuzu_emu.adapters
5 5
6import android.view.LayoutInflater 6import android.view.LayoutInflater
7import android.view.View
8import android.view.ViewGroup 7import android.view.ViewGroup
9import androidx.core.content.res.ResourcesCompat 8import androidx.core.content.res.ResourcesCompat
10import androidx.fragment.app.Fragment 9import androidx.fragment.app.Fragment
11import androidx.navigation.fragment.findNavController 10import androidx.navigation.fragment.findNavController
12import androidx.recyclerview.widget.RecyclerView
13import org.yuzu.yuzu_emu.HomeNavigationDirections 11import org.yuzu.yuzu_emu.HomeNavigationDirections
14import org.yuzu.yuzu_emu.NativeLibrary 12import org.yuzu.yuzu_emu.NativeLibrary
15import org.yuzu.yuzu_emu.R 13import org.yuzu.yuzu_emu.R
@@ -19,54 +17,43 @@ import org.yuzu.yuzu_emu.model.CabinetMode
19import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder 17import org.yuzu.yuzu_emu.adapters.CabinetLauncherDialogAdapter.CabinetModeViewHolder
20import org.yuzu.yuzu_emu.model.AppletInfo 18import org.yuzu.yuzu_emu.model.AppletInfo
21import org.yuzu.yuzu_emu.model.Game 19import org.yuzu.yuzu_emu.model.Game
20import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
22 21
23class CabinetLauncherDialogAdapter(val fragment: Fragment) : 22class CabinetLauncherDialogAdapter(val fragment: Fragment) :
24 RecyclerView.Adapter<CabinetModeViewHolder>(), 23 AbstractListAdapter<CabinetMode, CabinetModeViewHolder>(
25 View.OnClickListener { 24 CabinetMode.values().copyOfRange(1, CabinetMode.entries.size).toList()
26 private val cabinetModes = CabinetMode.values().copyOfRange(1, CabinetMode.values().size) 25 ) {
27 26
28 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder { 27 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CabinetModeViewHolder {
29 DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) 28 DialogListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
30 .apply { root.setOnClickListener(this@CabinetLauncherDialogAdapter) }
31 .also { return CabinetModeViewHolder(it) } 29 .also { return CabinetModeViewHolder(it) }
32 } 30 }
33 31
34 override fun getItemCount(): Int = cabinetModes.size
35
36 override fun onBindViewHolder(holder: CabinetModeViewHolder, position: Int) =
37 holder.bind(cabinetModes[position])
38
39 override fun onClick(view: View) {
40 val mode = (view.tag as CabinetModeViewHolder).cabinetMode
41 val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId)
42 NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId)
43 NativeLibrary.setCabinetMode(mode.id)
44 val appletGame = Game(
45 title = YuzuApplication.appContext.getString(R.string.cabinet_applet),
46 path = appletPath
47 )
48 val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
49 fragment.findNavController().navigate(action)
50 }
51
52 inner class CabinetModeViewHolder(val binding: DialogListItemBinding) : 32 inner class CabinetModeViewHolder(val binding: DialogListItemBinding) :
53 RecyclerView.ViewHolder(binding.root) { 33 AbstractViewHolder<CabinetMode>(binding) {
54 lateinit var cabinetMode: CabinetMode 34 override fun bind(model: CabinetMode) {
55
56 init {
57 itemView.tag = this
58 }
59
60 fun bind(cabinetMode: CabinetMode) {
61 this.cabinetMode = cabinetMode
62 binding.icon.setImageDrawable( 35 binding.icon.setImageDrawable(
63 ResourcesCompat.getDrawable( 36 ResourcesCompat.getDrawable(
64 binding.icon.context.resources, 37 binding.icon.context.resources,
65 cabinetMode.iconId, 38 model.iconId,
66 binding.icon.context.theme 39 binding.icon.context.theme
67 ) 40 )
68 ) 41 )
69 binding.title.setText(cabinetMode.titleId) 42 binding.title.setText(model.titleId)
43
44 binding.root.setOnClickListener { onClick(model) }
45 }
46
47 private fun onClick(mode: CabinetMode) {
48 val appletPath = NativeLibrary.getAppletLaunchPath(AppletInfo.Cabinet.entryId)
49 NativeLibrary.setCurrentAppletId(AppletInfo.Cabinet.appletId)
50 NativeLibrary.setCabinetMode(mode.id)
51 val appletGame = Game(
52 title = YuzuApplication.appContext.getString(R.string.cabinet_applet),
53 path = appletPath
54 )
55 val action = HomeNavigationDirections.actionGlobalEmulationActivity(appletGame)
56 fragment.findNavController().navigate(action)
70 } 57 }
71 } 58 }
72} 59}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
index d290a656c..d6f17cf29 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
@@ -7,65 +7,39 @@ import android.text.TextUtils
7import android.view.LayoutInflater 7import android.view.LayoutInflater
8import android.view.View 8import android.view.View
9import android.view.ViewGroup 9import android.view.ViewGroup
10import androidx.recyclerview.widget.AsyncDifferConfig
11import androidx.recyclerview.widget.DiffUtil
12import androidx.recyclerview.widget.ListAdapter
13import androidx.recyclerview.widget.RecyclerView
14import org.yuzu.yuzu_emu.R
15import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding 10import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding
11import org.yuzu.yuzu_emu.features.settings.model.StringSetting
12import org.yuzu.yuzu_emu.model.Driver
16import org.yuzu.yuzu_emu.model.DriverViewModel 13import org.yuzu.yuzu_emu.model.DriverViewModel
17import org.yuzu.yuzu_emu.utils.GpuDriverHelper 14import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
18import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
19 15
20class DriverAdapter(private val driverViewModel: DriverViewModel) : 16class DriverAdapter(private val driverViewModel: DriverViewModel) :
21 ListAdapter<Pair<String, GpuDriverMetadata>, DriverAdapter.DriverViewHolder>( 17 AbstractSingleSelectionList<Driver, DriverAdapter.DriverViewHolder>(
22 AsyncDifferConfig.Builder(DiffCallback()).build() 18 driverViewModel.driverList.value
23 ) { 19 ) {
24 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder { 20 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverViewHolder {
25 val binding = 21 CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
26 CardDriverOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) 22 .also { return DriverViewHolder(it) }
27 return DriverViewHolder(binding)
28 }
29
30 override fun getItemCount(): Int = currentList.size
31
32 override fun onBindViewHolder(holder: DriverViewHolder, position: Int) =
33 holder.bind(currentList[position])
34
35 private fun onSelectDriver(position: Int) {
36 driverViewModel.setSelectedDriverIndex(position)
37 notifyItemChanged(driverViewModel.previouslySelectedDriver)
38 notifyItemChanged(driverViewModel.selectedDriver)
39 }
40
41 private fun onDeleteDriver(driverData: Pair<String, GpuDriverMetadata>, position: Int) {
42 if (driverViewModel.selectedDriver > position) {
43 driverViewModel.setSelectedDriverIndex(driverViewModel.selectedDriver - 1)
44 }
45 if (GpuDriverHelper.customDriverSettingData == driverData.second) {
46 driverViewModel.setSelectedDriverIndex(0)
47 }
48 driverViewModel.driversToDelete.add(driverData.first)
49 driverViewModel.removeDriver(driverData)
50 notifyItemRemoved(position)
51 notifyItemChanged(driverViewModel.selectedDriver)
52 } 23 }
53 24
54 inner class DriverViewHolder(val binding: CardDriverOptionBinding) : 25 inner class DriverViewHolder(val binding: CardDriverOptionBinding) :
55 RecyclerView.ViewHolder(binding.root) { 26 AbstractViewHolder<Driver>(binding) {
56 private lateinit var driverData: Pair<String, GpuDriverMetadata> 27 override fun bind(model: Driver) {
57
58 fun bind(driverData: Pair<String, GpuDriverMetadata>) {
59 this.driverData = driverData
60 val driver = driverData.second
61
62 binding.apply { 28 binding.apply {
63 radioButton.isChecked = driverViewModel.selectedDriver == bindingAdapterPosition 29 radioButton.isChecked = model.selected
64 root.setOnClickListener { 30 root.setOnClickListener {
65 onSelectDriver(bindingAdapterPosition) 31 selectItem(bindingAdapterPosition) {
32 driverViewModel.onDriverSelected(it)
33 driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
34 }
66 } 35 }
67 buttonDelete.setOnClickListener { 36 buttonDelete.setOnClickListener {
68 onDeleteDriver(driverData, bindingAdapterPosition) 37 removeSelectableItem(
38 bindingAdapterPosition
39 ) { removedPosition: Int, selectedPosition: Int ->
40 driverViewModel.onDriverRemoved(removedPosition, selectedPosition)
41 driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
42 }
69 } 43 }
70 44
71 // Delay marquee by 3s 45 // Delay marquee by 3s
@@ -80,38 +54,19 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
80 }, 54 },
81 3000 55 3000
82 ) 56 )
83 if (driver.name == null) { 57 title.text = model.title
84 title.setText(R.string.system_gpu_driver) 58 version.text = model.version
85 description.text = "" 59 description.text = model.description
86 version.text = "" 60 if (model.description.isNotEmpty()) {
87 version.visibility = View.GONE
88 description.visibility = View.GONE
89 buttonDelete.visibility = View.GONE
90 } else {
91 title.text = driver.name
92 version.text = driver.version
93 description.text = driver.description
94 version.visibility = View.VISIBLE 61 version.visibility = View.VISIBLE
95 description.visibility = View.VISIBLE 62 description.visibility = View.VISIBLE
96 buttonDelete.visibility = View.VISIBLE 63 buttonDelete.visibility = View.VISIBLE
64 } else {
65 version.visibility = View.GONE
66 description.visibility = View.GONE
67 buttonDelete.visibility = View.GONE
97 } 68 }
98 } 69 }
99 } 70 }
100 } 71 }
101
102 private class DiffCallback : DiffUtil.ItemCallback<Pair<String, GpuDriverMetadata>>() {
103 override fun areItemsTheSame(
104 oldItem: Pair<String, GpuDriverMetadata>,
105 newItem: Pair<String, GpuDriverMetadata>
106 ): Boolean {
107 return oldItem.first == newItem.first
108 }
109
110 override fun areContentsTheSame(
111 oldItem: Pair<String, GpuDriverMetadata>,
112 newItem: Pair<String, GpuDriverMetadata>
113 ): Boolean {
114 return oldItem.second == newItem.second
115 }
116 }
117} 72}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt
index ab657a7b9..3d8f0bda8 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/FolderAdapter.kt
@@ -8,19 +8,14 @@ import android.text.TextUtils
8import android.view.LayoutInflater 8import android.view.LayoutInflater
9import android.view.ViewGroup 9import android.view.ViewGroup
10import androidx.fragment.app.FragmentActivity 10import androidx.fragment.app.FragmentActivity
11import androidx.recyclerview.widget.AsyncDifferConfig
12import androidx.recyclerview.widget.DiffUtil
13import androidx.recyclerview.widget.ListAdapter
14import androidx.recyclerview.widget.RecyclerView
15import org.yuzu.yuzu_emu.databinding.CardFolderBinding 11import org.yuzu.yuzu_emu.databinding.CardFolderBinding
16import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment 12import org.yuzu.yuzu_emu.fragments.GameFolderPropertiesDialogFragment
17import org.yuzu.yuzu_emu.model.GameDir 13import org.yuzu.yuzu_emu.model.GameDir
18import org.yuzu.yuzu_emu.model.GamesViewModel 14import org.yuzu.yuzu_emu.model.GamesViewModel
15import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
19 16
20class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) : 17class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesViewModel) :
21 ListAdapter<GameDir, FolderAdapter.FolderViewHolder>( 18 AbstractDiffAdapter<GameDir, FolderAdapter.FolderViewHolder>() {
22 AsyncDifferConfig.Builder(DiffCallback()).build()
23 ) {
24 override fun onCreateViewHolder( 19 override fun onCreateViewHolder(
25 parent: ViewGroup, 20 parent: ViewGroup,
26 viewType: Int 21 viewType: Int
@@ -29,18 +24,11 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
29 .also { return FolderViewHolder(it) } 24 .also { return FolderViewHolder(it) }
30 } 25 }
31 26
32 override fun onBindViewHolder(holder: FolderAdapter.FolderViewHolder, position: Int) =
33 holder.bind(currentList[position])
34
35 inner class FolderViewHolder(val binding: CardFolderBinding) : 27 inner class FolderViewHolder(val binding: CardFolderBinding) :
36 RecyclerView.ViewHolder(binding.root) { 28 AbstractViewHolder<GameDir>(binding) {
37 private lateinit var gameDir: GameDir 29 override fun bind(model: GameDir) {
38
39 fun bind(gameDir: GameDir) {
40 this.gameDir = gameDir
41
42 binding.apply { 30 binding.apply {
43 path.text = Uri.parse(gameDir.uriString).path 31 path.text = Uri.parse(model.uriString).path
44 path.postDelayed( 32 path.postDelayed(
45 { 33 {
46 path.isSelected = true 34 path.isSelected = true
@@ -50,7 +38,7 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
50 ) 38 )
51 39
52 buttonEdit.setOnClickListener { 40 buttonEdit.setOnClickListener {
53 GameFolderPropertiesDialogFragment.newInstance(this@FolderViewHolder.gameDir) 41 GameFolderPropertiesDialogFragment.newInstance(model)
54 .show( 42 .show(
55 activity.supportFragmentManager, 43 activity.supportFragmentManager,
56 GameFolderPropertiesDialogFragment.TAG 44 GameFolderPropertiesDialogFragment.TAG
@@ -58,19 +46,9 @@ class FolderAdapter(val activity: FragmentActivity, val gamesViewModel: GamesVie
58 } 46 }
59 47
60 buttonDelete.setOnClickListener { 48 buttonDelete.setOnClickListener {
61 gamesViewModel.removeFolder(this@FolderViewHolder.gameDir) 49 gamesViewModel.removeFolder(model)
62 } 50 }
63 } 51 }
64 } 52 }
65 } 53 }
66
67 private class DiffCallback : DiffUtil.ItemCallback<GameDir>() {
68 override fun areItemsTheSame(oldItem: GameDir, newItem: GameDir): Boolean {
69 return oldItem == newItem
70 }
71
72 override fun areContentsTheSame(oldItem: GameDir, newItem: GameDir): Boolean {
73 return oldItem == newItem
74 }
75 }
76} 54}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
index a578f0de8..e26c2e0ab 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
@@ -9,7 +9,6 @@ import android.graphics.drawable.LayerDrawable
9import android.net.Uri 9import android.net.Uri
10import android.text.TextUtils 10import android.text.TextUtils
11import android.view.LayoutInflater 11import android.view.LayoutInflater
12import android.view.View
13import android.view.ViewGroup 12import android.view.ViewGroup
14import android.widget.ImageView 13import android.widget.ImageView
15import android.widget.Toast 14import android.widget.Toast
@@ -25,10 +24,6 @@ import androidx.lifecycle.ViewModelProvider
25import androidx.lifecycle.lifecycleScope 24import androidx.lifecycle.lifecycleScope
26import androidx.navigation.findNavController 25import androidx.navigation.findNavController
27import androidx.preference.PreferenceManager 26import androidx.preference.PreferenceManager
28import androidx.recyclerview.widget.AsyncDifferConfig
29import androidx.recyclerview.widget.DiffUtil
30import androidx.recyclerview.widget.ListAdapter
31import androidx.recyclerview.widget.RecyclerView
32import kotlinx.coroutines.Dispatchers 27import kotlinx.coroutines.Dispatchers
33import kotlinx.coroutines.launch 28import kotlinx.coroutines.launch
34import kotlinx.coroutines.withContext 29import kotlinx.coroutines.withContext
@@ -36,122 +31,26 @@ import org.yuzu.yuzu_emu.HomeNavigationDirections
36import org.yuzu.yuzu_emu.R 31import org.yuzu.yuzu_emu.R
37import org.yuzu.yuzu_emu.YuzuApplication 32import org.yuzu.yuzu_emu.YuzuApplication
38import org.yuzu.yuzu_emu.activities.EmulationActivity 33import org.yuzu.yuzu_emu.activities.EmulationActivity
39import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder
40import org.yuzu.yuzu_emu.databinding.CardGameBinding 34import org.yuzu.yuzu_emu.databinding.CardGameBinding
41import org.yuzu.yuzu_emu.model.Game 35import org.yuzu.yuzu_emu.model.Game
42import org.yuzu.yuzu_emu.model.GamesViewModel 36import org.yuzu.yuzu_emu.model.GamesViewModel
43import org.yuzu.yuzu_emu.utils.GameIconUtils 37import org.yuzu.yuzu_emu.utils.GameIconUtils
38import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
44 39
45class GameAdapter(private val activity: AppCompatActivity) : 40class GameAdapter(private val activity: AppCompatActivity) :
46 ListAdapter<Game, GameViewHolder>(AsyncDifferConfig.Builder(DiffCallback()).build()), 41 AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>() {
47 View.OnClickListener,
48 View.OnLongClickListener {
49 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder { 42 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameViewHolder {
50 // Create a new view. 43 CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
51 val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false) 44 .also { return GameViewHolder(it) }
52 binding.cardGame.setOnClickListener(this)
53 binding.cardGame.setOnLongClickListener(this)
54
55 // Use that view to create a ViewHolder.
56 return GameViewHolder(binding)
57 }
58
59 override fun onBindViewHolder(holder: GameViewHolder, position: Int) =
60 holder.bind(currentList[position])
61
62 override fun getItemCount(): Int = currentList.size
63
64 /**
65 * Launches the game that was clicked on.
66 *
67 * @param view The card representing the game the user wants to play.
68 */
69 override fun onClick(view: View) {
70 val holder = view.tag as GameViewHolder
71
72 val gameExists = DocumentFile.fromSingleUri(
73 YuzuApplication.appContext,
74 Uri.parse(holder.game.path)
75 )?.exists() == true
76 if (!gameExists) {
77 Toast.makeText(
78 YuzuApplication.appContext,
79 R.string.loader_error_file_not_found,
80 Toast.LENGTH_LONG
81 ).show()
82
83 ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true)
84 return
85 }
86
87 val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
88 preferences.edit()
89 .putLong(
90 holder.game.keyLastPlayedTime,
91 System.currentTimeMillis()
92 )
93 .apply()
94
95 val openIntent = Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
96 action = Intent.ACTION_VIEW
97 data = Uri.parse(holder.game.path)
98 }
99
100 activity.lifecycleScope.launch {
101 withContext(Dispatchers.IO) {
102 val layerDrawable = ResourcesCompat.getDrawable(
103 YuzuApplication.appContext.resources,
104 R.drawable.shortcut,
105 null
106 ) as LayerDrawable
107 layerDrawable.setDrawableByLayerId(
108 R.id.shortcut_foreground,
109 GameIconUtils.getGameIcon(activity, holder.game)
110 .toDrawable(YuzuApplication.appContext.resources)
111 )
112 val inset = YuzuApplication.appContext.resources
113 .getDimensionPixelSize(R.dimen.icon_inset)
114 layerDrawable.setLayerInset(1, inset, inset, inset, inset)
115 val shortcut =
116 ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
117 .setShortLabel(holder.game.title)
118 .setIcon(
119 IconCompat.createWithAdaptiveBitmap(
120 layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
121 )
122 )
123 .setIntent(openIntent)
124 .build()
125 ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
126 }
127 }
128
129 val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game, true)
130 view.findNavController().navigate(action)
131 }
132
133 override fun onLongClick(view: View): Boolean {
134 val holder = view.tag as GameViewHolder
135 val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(holder.game)
136 view.findNavController().navigate(action)
137 return true
138 } 45 }
139 46
140 inner class GameViewHolder(val binding: CardGameBinding) : 47 inner class GameViewHolder(val binding: CardGameBinding) :
141 RecyclerView.ViewHolder(binding.root) { 48 AbstractViewHolder<Game>(binding) {
142 lateinit var game: Game 49 override fun bind(model: Game) {
143
144 init {
145 binding.cardGame.tag = this
146 }
147
148 fun bind(game: Game) {
149 this.game = game
150
151 binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP 50 binding.imageGameScreen.scaleType = ImageView.ScaleType.CENTER_CROP
152 GameIconUtils.loadGameIcon(game, binding.imageGameScreen) 51 GameIconUtils.loadGameIcon(model, binding.imageGameScreen)
153 52
154 binding.textGameTitle.text = game.title.replace("[\\t\\n\\r]+".toRegex(), " ") 53 binding.textGameTitle.text = model.title.replace("[\\t\\n\\r]+".toRegex(), " ")
155 54
156 binding.textGameTitle.postDelayed( 55 binding.textGameTitle.postDelayed(
157 { 56 {
@@ -160,16 +59,79 @@ class GameAdapter(private val activity: AppCompatActivity) :
160 }, 59 },
161 3000 60 3000
162 ) 61 )
62
63 binding.cardGame.setOnClickListener { onClick(model) }
64 binding.cardGame.setOnLongClickListener { onLongClick(model) }
163 } 65 }
164 }
165 66
166 private class DiffCallback : DiffUtil.ItemCallback<Game>() { 67 fun onClick(game: Game) {
167 override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean { 68 val gameExists = DocumentFile.fromSingleUri(
168 return oldItem == newItem 69 YuzuApplication.appContext,
70 Uri.parse(game.path)
71 )?.exists() == true
72 if (!gameExists) {
73 Toast.makeText(
74 YuzuApplication.appContext,
75 R.string.loader_error_file_not_found,
76 Toast.LENGTH_LONG
77 ).show()
78
79 ViewModelProvider(activity)[GamesViewModel::class.java].reloadGames(true)
80 return
81 }
82
83 val preferences =
84 PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
85 preferences.edit()
86 .putLong(
87 game.keyLastPlayedTime,
88 System.currentTimeMillis()
89 )
90 .apply()
91
92 val openIntent =
93 Intent(YuzuApplication.appContext, EmulationActivity::class.java).apply {
94 action = Intent.ACTION_VIEW
95 data = Uri.parse(game.path)
96 }
97
98 activity.lifecycleScope.launch {
99 withContext(Dispatchers.IO) {
100 val layerDrawable = ResourcesCompat.getDrawable(
101 YuzuApplication.appContext.resources,
102 R.drawable.shortcut,
103 null
104 ) as LayerDrawable
105 layerDrawable.setDrawableByLayerId(
106 R.id.shortcut_foreground,
107 GameIconUtils.getGameIcon(activity, game)
108 .toDrawable(YuzuApplication.appContext.resources)
109 )
110 val inset = YuzuApplication.appContext.resources
111 .getDimensionPixelSize(R.dimen.icon_inset)
112 layerDrawable.setLayerInset(1, inset, inset, inset, inset)
113 val shortcut =
114 ShortcutInfoCompat.Builder(YuzuApplication.appContext, game.path)
115 .setShortLabel(game.title)
116 .setIcon(
117 IconCompat.createWithAdaptiveBitmap(
118 layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
119 )
120 )
121 .setIntent(openIntent)
122 .build()
123 ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
124 }
125 }
126
127 val action = HomeNavigationDirections.actionGlobalEmulationActivity(game, true)
128 binding.root.findNavController().navigate(action)
169 } 129 }
170 130
171 override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { 131 fun onLongClick(game: Game): Boolean {
172 return oldItem == newItem 132 val action = HomeNavigationDirections.actionGlobalPerGamePropertiesFragment(game)
133 binding.root.findNavController().navigate(action)
134 return true
173 } 135 }
174 } 136 }
175} 137}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt
index 95841d786..0046d5314 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GamePropertiesAdapter.kt
@@ -12,23 +12,22 @@ import androidx.lifecycle.Lifecycle
12import androidx.lifecycle.LifecycleOwner 12import androidx.lifecycle.LifecycleOwner
13import androidx.lifecycle.lifecycleScope 13import androidx.lifecycle.lifecycleScope
14import androidx.lifecycle.repeatOnLifecycle 14import androidx.lifecycle.repeatOnLifecycle
15import androidx.recyclerview.widget.RecyclerView
16import kotlinx.coroutines.launch 15import kotlinx.coroutines.launch
17import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding 16import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
18import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding 17import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
19import org.yuzu.yuzu_emu.model.GameProperty 18import org.yuzu.yuzu_emu.model.GameProperty
20import org.yuzu.yuzu_emu.model.InstallableProperty 19import org.yuzu.yuzu_emu.model.InstallableProperty
21import org.yuzu.yuzu_emu.model.SubmenuProperty 20import org.yuzu.yuzu_emu.model.SubmenuProperty
21import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
22 22
23class GamePropertiesAdapter( 23class GamePropertiesAdapter(
24 private val viewLifecycle: LifecycleOwner, 24 private val viewLifecycle: LifecycleOwner,
25 private var properties: List<GameProperty> 25 private var properties: List<GameProperty>
26) : 26) : AbstractListAdapter<GameProperty, AbstractViewHolder<GameProperty>>(properties) {
27 RecyclerView.Adapter<GamePropertiesAdapter.GamePropertyViewHolder>() {
28 override fun onCreateViewHolder( 27 override fun onCreateViewHolder(
29 parent: ViewGroup, 28 parent: ViewGroup,
30 viewType: Int 29 viewType: Int
31 ): GamePropertyViewHolder { 30 ): AbstractViewHolder<GameProperty> {
32 val inflater = LayoutInflater.from(parent.context) 31 val inflater = LayoutInflater.from(parent.context)
33 return when (viewType) { 32 return when (viewType) {
34 PropertyType.Submenu.ordinal -> { 33 PropertyType.Submenu.ordinal -> {
@@ -51,11 +50,6 @@ class GamePropertiesAdapter(
51 } 50 }
52 } 51 }
53 52
54 override fun getItemCount(): Int = properties.size
55
56 override fun onBindViewHolder(holder: GamePropertyViewHolder, position: Int) =
57 holder.bind(properties[position])
58
59 override fun getItemViewType(position: Int): Int { 53 override fun getItemViewType(position: Int): Int {
60 return when (properties[position]) { 54 return when (properties[position]) {
61 is SubmenuProperty -> PropertyType.Submenu.ordinal 55 is SubmenuProperty -> PropertyType.Submenu.ordinal
@@ -63,14 +57,10 @@ class GamePropertiesAdapter(
63 } 57 }
64 } 58 }
65 59
66 sealed class GamePropertyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
67 abstract fun bind(property: GameProperty)
68 }
69
70 inner class SubmenuPropertyViewHolder(val binding: CardSimpleOutlinedBinding) : 60 inner class SubmenuPropertyViewHolder(val binding: CardSimpleOutlinedBinding) :
71 GamePropertyViewHolder(binding.root) { 61 AbstractViewHolder<GameProperty>(binding) {
72 override fun bind(property: GameProperty) { 62 override fun bind(model: GameProperty) {
73 val submenuProperty = property as SubmenuProperty 63 val submenuProperty = model as SubmenuProperty
74 64
75 binding.root.setOnClickListener { 65 binding.root.setOnClickListener {
76 submenuProperty.action.invoke() 66 submenuProperty.action.invoke()
@@ -108,9 +98,9 @@ class GamePropertiesAdapter(
108 } 98 }
109 99
110 inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) : 100 inner class InstallablePropertyViewHolder(val binding: CardInstallableIconBinding) :
111 GamePropertyViewHolder(binding.root) { 101 AbstractViewHolder<GameProperty>(binding) {
112 override fun bind(property: GameProperty) { 102 override fun bind(model: GameProperty) {
113 val installableProperty = property as InstallableProperty 103 val installableProperty = model as InstallableProperty
114 104
115 binding.title.setText(installableProperty.titleId) 105 binding.title.setText(installableProperty.titleId)
116 binding.description.setText(installableProperty.descriptionId) 106 binding.description.setText(installableProperty.descriptionId)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
index 58ce343f4..b512845d5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
@@ -14,69 +14,37 @@ import androidx.lifecycle.Lifecycle
14import androidx.lifecycle.LifecycleOwner 14import androidx.lifecycle.LifecycleOwner
15import androidx.lifecycle.lifecycleScope 15import androidx.lifecycle.lifecycleScope
16import androidx.lifecycle.repeatOnLifecycle 16import androidx.lifecycle.repeatOnLifecycle
17import androidx.recyclerview.widget.RecyclerView
18import kotlinx.coroutines.launch 17import kotlinx.coroutines.launch
19import org.yuzu.yuzu_emu.R 18import org.yuzu.yuzu_emu.R
20import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding 19import org.yuzu.yuzu_emu.databinding.CardHomeOptionBinding
21import org.yuzu.yuzu_emu.fragments.MessageDialogFragment 20import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
22import org.yuzu.yuzu_emu.model.HomeSetting 21import org.yuzu.yuzu_emu.model.HomeSetting
22import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
23 23
24class HomeSettingAdapter( 24class HomeSettingAdapter(
25 private val activity: AppCompatActivity, 25 private val activity: AppCompatActivity,
26 private val viewLifecycle: LifecycleOwner, 26 private val viewLifecycle: LifecycleOwner,
27 var options: List<HomeSetting> 27 options: List<HomeSetting>
28) : 28) : AbstractListAdapter<HomeSetting, HomeSettingAdapter.HomeOptionViewHolder>(options) {
29 RecyclerView.Adapter<HomeSettingAdapter.HomeOptionViewHolder>(),
30 View.OnClickListener {
31 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder { 29 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOptionViewHolder {
32 val binding = 30 CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
33 CardHomeOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false) 31 .also { return HomeOptionViewHolder(it) }
34 binding.root.setOnClickListener(this)
35 return HomeOptionViewHolder(binding)
36 }
37
38 override fun getItemCount(): Int {
39 return options.size
40 }
41
42 override fun onBindViewHolder(holder: HomeOptionViewHolder, position: Int) {
43 holder.bind(options[position])
44 }
45
46 override fun onClick(view: View) {
47 val holder = view.tag as HomeOptionViewHolder
48 if (holder.option.isEnabled.invoke()) {
49 holder.option.onClick.invoke()
50 } else {
51 MessageDialogFragment.newInstance(
52 activity,
53 titleId = holder.option.disabledTitleId,
54 descriptionId = holder.option.disabledMessageId
55 ).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
56 }
57 } 32 }
58 33
59 inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) : 34 inner class HomeOptionViewHolder(val binding: CardHomeOptionBinding) :
60 RecyclerView.ViewHolder(binding.root) { 35 AbstractViewHolder<HomeSetting>(binding) {
61 lateinit var option: HomeSetting 36 override fun bind(model: HomeSetting) {
62 37 binding.optionTitle.text = activity.resources.getString(model.titleId)
63 init { 38 binding.optionDescription.text = activity.resources.getString(model.descriptionId)
64 itemView.tag = this
65 }
66
67 fun bind(option: HomeSetting) {
68 this.option = option
69 binding.optionTitle.text = activity.resources.getString(option.titleId)
70 binding.optionDescription.text = activity.resources.getString(option.descriptionId)
71 binding.optionIcon.setImageDrawable( 39 binding.optionIcon.setImageDrawable(
72 ResourcesCompat.getDrawable( 40 ResourcesCompat.getDrawable(
73 activity.resources, 41 activity.resources,
74 option.iconId, 42 model.iconId,
75 activity.theme 43 activity.theme
76 ) 44 )
77 ) 45 )
78 46
79 when (option.titleId) { 47 when (model.titleId) {
80 R.string.get_early_access -> 48 R.string.get_early_access ->
81 binding.optionLayout.background = 49 binding.optionLayout.background =
82 ContextCompat.getDrawable( 50 ContextCompat.getDrawable(
@@ -85,7 +53,7 @@ class HomeSettingAdapter(
85 ) 53 )
86 } 54 }
87 55
88 if (!option.isEnabled.invoke()) { 56 if (!model.isEnabled.invoke()) {
89 binding.optionTitle.alpha = 0.5f 57 binding.optionTitle.alpha = 0.5f
90 binding.optionDescription.alpha = 0.5f 58 binding.optionDescription.alpha = 0.5f
91 binding.optionIcon.alpha = 0.5f 59 binding.optionIcon.alpha = 0.5f
@@ -93,7 +61,7 @@ class HomeSettingAdapter(
93 61
94 viewLifecycle.lifecycleScope.launch { 62 viewLifecycle.lifecycleScope.launch {
95 viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) { 63 viewLifecycle.repeatOnLifecycle(Lifecycle.State.CREATED) {
96 option.details.collect { updateOptionDetails(it) } 64 model.details.collect { updateOptionDetails(it) }
97 } 65 }
98 } 66 }
99 binding.optionDetail.postDelayed( 67 binding.optionDetail.postDelayed(
@@ -103,6 +71,20 @@ class HomeSettingAdapter(
103 }, 71 },
104 3000 72 3000
105 ) 73 )
74
75 binding.root.setOnClickListener { onClick(model) }
76 }
77
78 private fun onClick(model: HomeSetting) {
79 if (model.isEnabled.invoke()) {
80 model.onClick.invoke()
81 } else {
82 MessageDialogFragment.newInstance(
83 activity,
84 titleId = model.disabledTitleId,
85 descriptionId = model.disabledMessageId
86 ).show(activity.supportFragmentManager, MessageDialogFragment.TAG)
87 }
106 } 88 }
107 89
108 private fun updateOptionDetails(detailString: String) { 90 private fun updateOptionDetails(detailString: String) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt
index e960fbaab..4218c4e52 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/InstallableAdapter.kt
@@ -6,43 +6,33 @@ package org.yuzu.yuzu_emu.adapters
6import android.view.LayoutInflater 6import android.view.LayoutInflater
7import android.view.View 7import android.view.View
8import android.view.ViewGroup 8import android.view.ViewGroup
9import androidx.recyclerview.widget.RecyclerView
10import org.yuzu.yuzu_emu.databinding.CardInstallableBinding 9import org.yuzu.yuzu_emu.databinding.CardInstallableBinding
11import org.yuzu.yuzu_emu.model.Installable 10import org.yuzu.yuzu_emu.model.Installable
11import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
12 12
13class InstallableAdapter(private val installables: List<Installable>) : 13class InstallableAdapter(installables: List<Installable>) :
14 RecyclerView.Adapter<InstallableAdapter.InstallableViewHolder>() { 14 AbstractListAdapter<Installable, InstallableAdapter.InstallableViewHolder>(installables) {
15 override fun onCreateViewHolder( 15 override fun onCreateViewHolder(
16 parent: ViewGroup, 16 parent: ViewGroup,
17 viewType: Int 17 viewType: Int
18 ): InstallableAdapter.InstallableViewHolder { 18 ): InstallableAdapter.InstallableViewHolder {
19 val binding = 19 CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false)
20 CardInstallableBinding.inflate(LayoutInflater.from(parent.context), parent, false) 20 .also { return InstallableViewHolder(it) }
21 return InstallableViewHolder(binding)
22 } 21 }
23 22
24 override fun getItemCount(): Int = installables.size
25
26 override fun onBindViewHolder(holder: InstallableAdapter.InstallableViewHolder, position: Int) =
27 holder.bind(installables[position])
28
29 inner class InstallableViewHolder(val binding: CardInstallableBinding) : 23 inner class InstallableViewHolder(val binding: CardInstallableBinding) :
30 RecyclerView.ViewHolder(binding.root) { 24 AbstractViewHolder<Installable>(binding) {
31 lateinit var installable: Installable 25 override fun bind(model: Installable) {
32 26 binding.title.setText(model.titleId)
33 fun bind(installable: Installable) { 27 binding.description.setText(model.descriptionId)
34 this.installable = installable
35
36 binding.title.setText(installable.titleId)
37 binding.description.setText(installable.descriptionId)
38 28
39 if (installable.install != null) { 29 if (model.install != null) {
40 binding.buttonInstall.visibility = View.VISIBLE 30 binding.buttonInstall.visibility = View.VISIBLE
41 binding.buttonInstall.setOnClickListener { installable.install.invoke() } 31 binding.buttonInstall.setOnClickListener { model.install.invoke() }
42 } 32 }
43 if (installable.export != null) { 33 if (model.export != null) {
44 binding.buttonExport.visibility = View.VISIBLE 34 binding.buttonExport.visibility = View.VISIBLE
45 binding.buttonExport.setOnClickListener { installable.export.invoke() } 35 binding.buttonExport.setOnClickListener { model.export.invoke() }
46 } 36 }
47 } 37 }
48 } 38 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt
index bc6ff1364..38bb1f96f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/LicenseAdapter.kt
@@ -7,49 +7,33 @@ import android.view.LayoutInflater
7import android.view.View 7import android.view.View
8import android.view.ViewGroup 8import android.view.ViewGroup
9import androidx.appcompat.app.AppCompatActivity 9import androidx.appcompat.app.AppCompatActivity
10import androidx.recyclerview.widget.RecyclerView
11import androidx.recyclerview.widget.RecyclerView.ViewHolder
12import org.yuzu.yuzu_emu.YuzuApplication
13import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding 10import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
14import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment 11import org.yuzu.yuzu_emu.fragments.LicenseBottomSheetDialogFragment
15import org.yuzu.yuzu_emu.model.License 12import org.yuzu.yuzu_emu.model.License
13import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
16 14
17class LicenseAdapter(private val activity: AppCompatActivity, var licenses: List<License>) : 15class LicenseAdapter(private val activity: AppCompatActivity, licenses: List<License>) :
18 RecyclerView.Adapter<LicenseAdapter.LicenseViewHolder>(), 16 AbstractListAdapter<License, LicenseAdapter.LicenseViewHolder>(licenses) {
19 View.OnClickListener {
20 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder { 17 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LicenseViewHolder {
21 val binding = 18 ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false)
22 ListItemSettingBinding.inflate(LayoutInflater.from(parent.context), parent, false) 19 .also { return LicenseViewHolder(it) }
23 binding.root.setOnClickListener(this)
24 return LicenseViewHolder(binding)
25 } 20 }
26 21
27 override fun getItemCount(): Int = licenses.size 22 inner class LicenseViewHolder(val binding: ListItemSettingBinding) :
23 AbstractViewHolder<License>(binding) {
24 override fun bind(model: License) {
25 binding.apply {
26 textSettingName.text = root.context.getString(model.titleId)
27 textSettingDescription.text = root.context.getString(model.descriptionId)
28 textSettingValue.visibility = View.GONE
28 29
29 override fun onBindViewHolder(holder: LicenseViewHolder, position: Int) { 30 root.setOnClickListener { onClick(model) }
30 holder.bind(licenses[position]) 31 }
31 }
32
33 override fun onClick(view: View) {
34 val license = (view.tag as LicenseViewHolder).license
35 LicenseBottomSheetDialogFragment.newInstance(license)
36 .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG)
37 }
38
39 inner class LicenseViewHolder(val binding: ListItemSettingBinding) : ViewHolder(binding.root) {
40 lateinit var license: License
41
42 init {
43 itemView.tag = this
44 } 32 }
45 33
46 fun bind(license: License) { 34 private fun onClick(license: License) {
47 this.license = license 35 LicenseBottomSheetDialogFragment.newInstance(license)
48 36 .show(activity.supportFragmentManager, LicenseBottomSheetDialogFragment.TAG)
49 val context = YuzuApplication.appContext
50 binding.textSettingName.text = context.getString(license.titleId)
51 binding.textSettingDescription.text = context.getString(license.descriptionId)
52 binding.textSettingValue.visibility = View.GONE
53 } 37 }
54 } 38 }
55} 39}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
index 6b46d359e..02118e1a8 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/SetupAdapter.kt
@@ -10,7 +10,6 @@ import android.view.ViewGroup
10import androidx.appcompat.app.AppCompatActivity 10import androidx.appcompat.app.AppCompatActivity
11import androidx.core.content.res.ResourcesCompat 11import androidx.core.content.res.ResourcesCompat
12import androidx.lifecycle.ViewModelProvider 12import androidx.lifecycle.ViewModelProvider
13import androidx.recyclerview.widget.RecyclerView
14import com.google.android.material.button.MaterialButton 13import com.google.android.material.button.MaterialButton
15import org.yuzu.yuzu_emu.databinding.PageSetupBinding 14import org.yuzu.yuzu_emu.databinding.PageSetupBinding
16import org.yuzu.yuzu_emu.model.HomeViewModel 15import org.yuzu.yuzu_emu.model.HomeViewModel
@@ -18,31 +17,19 @@ import org.yuzu.yuzu_emu.model.SetupCallback
18import org.yuzu.yuzu_emu.model.SetupPage 17import org.yuzu.yuzu_emu.model.SetupPage
19import org.yuzu.yuzu_emu.model.StepState 18import org.yuzu.yuzu_emu.model.StepState
20import org.yuzu.yuzu_emu.utils.ViewUtils 19import org.yuzu.yuzu_emu.utils.ViewUtils
20import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
21 21
22class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>) : 22class SetupAdapter(val activity: AppCompatActivity, pages: List<SetupPage>) :
23 RecyclerView.Adapter<SetupAdapter.SetupPageViewHolder>() { 23 AbstractListAdapter<SetupPage, SetupAdapter.SetupPageViewHolder>(pages) {
24 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder { 24 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SetupPageViewHolder {
25 val binding = PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false) 25 PageSetupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
26 return SetupPageViewHolder(binding) 26 .also { return SetupPageViewHolder(it) }
27 } 27 }
28 28
29 override fun getItemCount(): Int = pages.size
30
31 override fun onBindViewHolder(holder: SetupPageViewHolder, position: Int) =
32 holder.bind(pages[position])
33
34 inner class SetupPageViewHolder(val binding: PageSetupBinding) : 29 inner class SetupPageViewHolder(val binding: PageSetupBinding) :
35 RecyclerView.ViewHolder(binding.root), SetupCallback { 30 AbstractViewHolder<SetupPage>(binding), SetupCallback {
36 lateinit var page: SetupPage 31 override fun bind(model: SetupPage) {
37 32 if (model.stepCompleted.invoke() == StepState.COMPLETE) {
38 init {
39 itemView.tag = this
40 }
41
42 fun bind(page: SetupPage) {
43 this.page = page
44
45 if (page.stepCompleted.invoke() == StepState.COMPLETE) {
46 binding.buttonAction.visibility = View.INVISIBLE 33 binding.buttonAction.visibility = View.INVISIBLE
47 binding.textConfirmation.visibility = View.VISIBLE 34 binding.textConfirmation.visibility = View.VISIBLE
48 } 35 }
@@ -50,31 +37,31 @@ class SetupAdapter(val activity: AppCompatActivity, val pages: List<SetupPage>)
50 binding.icon.setImageDrawable( 37 binding.icon.setImageDrawable(
51 ResourcesCompat.getDrawable( 38 ResourcesCompat.getDrawable(
52 activity.resources, 39 activity.resources,
53 page.iconId, 40 model.iconId,
54 activity.theme 41 activity.theme
55 ) 42 )
56 ) 43 )
57 binding.textTitle.text = activity.resources.getString(page.titleId) 44 binding.textTitle.text = activity.resources.getString(model.titleId)
58 binding.textDescription.text = 45 binding.textDescription.text =
59 Html.fromHtml(activity.resources.getString(page.descriptionId), 0) 46 Html.fromHtml(activity.resources.getString(model.descriptionId), 0)
60 47
61 binding.buttonAction.apply { 48 binding.buttonAction.apply {
62 text = activity.resources.getString(page.buttonTextId) 49 text = activity.resources.getString(model.buttonTextId)
63 if (page.buttonIconId != 0) { 50 if (model.buttonIconId != 0) {
64 icon = ResourcesCompat.getDrawable( 51 icon = ResourcesCompat.getDrawable(
65 activity.resources, 52 activity.resources,
66 page.buttonIconId, 53 model.buttonIconId,
67 activity.theme 54 activity.theme
68 ) 55 )
69 } 56 }
70 iconGravity = 57 iconGravity =
71 if (page.leftAlignedIcon) { 58 if (model.leftAlignedIcon) {
72 MaterialButton.ICON_GRAVITY_START 59 MaterialButton.ICON_GRAVITY_START
73 } else { 60 } else {
74 MaterialButton.ICON_GRAVITY_END 61 MaterialButton.ICON_GRAVITY_END
75 } 62 }
76 setOnClickListener { 63 setOnClickListener {
77 page.buttonAction.invoke(this@SetupPageViewHolder) 64 model.buttonAction.invoke(this@SetupPageViewHolder)
78 } 65 }
79 } 66 }
80 } 67 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
index a1620fbb7..5b5f800c1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
@@ -76,8 +76,8 @@ class AboutFragment : Fragment() {
76 binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment) 76 binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment)
77 } 77 }
78 78
79 binding.textBuildHash.text = BuildConfig.GIT_HASH 79 binding.textVersionName.text = BuildConfig.VERSION_NAME
80 binding.buttonBuildHash.setOnClickListener { 80 binding.textVersionName.setOnClickListener {
81 val clipBoard = 81 val clipBoard =
82 requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager 82 requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
83 val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH) 83 val clip = ClipData.newPlainText(getString(R.string.build), BuildConfig.GIT_HASH)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt
index cc71254dc..9dabb9c41 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverManagerFragment.kt
@@ -3,6 +3,7 @@
3 3
4package org.yuzu.yuzu_emu.fragments 4package org.yuzu.yuzu_emu.fragments
5 5
6import android.annotation.SuppressLint
6import android.os.Bundle 7import android.os.Bundle
7import android.view.LayoutInflater 8import android.view.LayoutInflater
8import android.view.View 9import android.view.View
@@ -13,20 +14,26 @@ import androidx.core.view.WindowInsetsCompat
13import androidx.core.view.updatePadding 14import androidx.core.view.updatePadding
14import androidx.fragment.app.Fragment 15import androidx.fragment.app.Fragment
15import androidx.fragment.app.activityViewModels 16import androidx.fragment.app.activityViewModels
17import androidx.lifecycle.Lifecycle
16import androidx.lifecycle.lifecycleScope 18import androidx.lifecycle.lifecycleScope
19import androidx.lifecycle.repeatOnLifecycle
17import androidx.navigation.findNavController 20import androidx.navigation.findNavController
18import androidx.navigation.fragment.navArgs 21import androidx.navigation.fragment.navArgs
19import androidx.recyclerview.widget.GridLayoutManager 22import androidx.recyclerview.widget.GridLayoutManager
20import com.google.android.material.transition.MaterialSharedAxis 23import com.google.android.material.transition.MaterialSharedAxis
21import kotlinx.coroutines.flow.collectLatest 24import kotlinx.coroutines.Dispatchers
22import kotlinx.coroutines.launch 25import kotlinx.coroutines.launch
26import kotlinx.coroutines.withContext
23import org.yuzu.yuzu_emu.R 27import org.yuzu.yuzu_emu.R
24import org.yuzu.yuzu_emu.adapters.DriverAdapter 28import org.yuzu.yuzu_emu.adapters.DriverAdapter
25import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding 29import org.yuzu.yuzu_emu.databinding.FragmentDriverManagerBinding
30import org.yuzu.yuzu_emu.features.settings.model.StringSetting
31import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
26import org.yuzu.yuzu_emu.model.DriverViewModel 32import org.yuzu.yuzu_emu.model.DriverViewModel
27import org.yuzu.yuzu_emu.model.HomeViewModel 33import org.yuzu.yuzu_emu.model.HomeViewModel
28import org.yuzu.yuzu_emu.utils.FileUtil 34import org.yuzu.yuzu_emu.utils.FileUtil
29import org.yuzu.yuzu_emu.utils.GpuDriverHelper 35import org.yuzu.yuzu_emu.utils.GpuDriverHelper
36import org.yuzu.yuzu_emu.utils.NativeConfig
30import java.io.File 37import java.io.File
31import java.io.IOException 38import java.io.IOException
32 39
@@ -55,12 +62,43 @@ class DriverManagerFragment : Fragment() {
55 return binding.root 62 return binding.root
56 } 63 }
57 64
65 // This is using the correct scope, lint is just acting up
66 @SuppressLint("UnsafeRepeatOnLifecycleDetector")
58 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 67 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
59 super.onViewCreated(view, savedInstanceState) 68 super.onViewCreated(view, savedInstanceState)
60 homeViewModel.setNavigationVisibility(visible = false, animated = true) 69 homeViewModel.setNavigationVisibility(visible = false, animated = true)
61 homeViewModel.setStatusBarShadeVisibility(visible = false) 70 homeViewModel.setStatusBarShadeVisibility(visible = false)
62 71
63 driverViewModel.onOpenDriverManager(args.game) 72 driverViewModel.onOpenDriverManager(args.game)
73 if (NativeConfig.isPerGameConfigLoaded()) {
74 binding.toolbarDrivers.inflateMenu(R.menu.menu_driver_manager)
75 driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
76 binding.toolbarDrivers.setOnMenuItemClickListener {
77 when (it.itemId) {
78 R.id.menu_driver_clear -> {
79 StringSetting.DRIVER_PATH.global = true
80 driverViewModel.updateDriverList()
81 (binding.listDrivers.adapter as DriverAdapter)
82 .replaceList(driverViewModel.driverList.value)
83 driverViewModel.showClearButton(false)
84 true
85 }
86
87 else -> false
88 }
89 }
90
91 viewLifecycleOwner.lifecycleScope.apply {
92 launch {
93 repeatOnLifecycle(Lifecycle.State.STARTED) {
94 driverViewModel.showClearButton.collect {
95 binding.toolbarDrivers.menu
96 .findItem(R.id.menu_driver_clear).isVisible = it
97 }
98 }
99 }
100 }
101 }
64 102
65 if (!driverViewModel.isInteractionAllowed.value) { 103 if (!driverViewModel.isInteractionAllowed.value) {
66 DriversLoadingDialogFragment().show( 104 DriversLoadingDialogFragment().show(
@@ -85,25 +123,6 @@ class DriverManagerFragment : Fragment() {
85 adapter = DriverAdapter(driverViewModel) 123 adapter = DriverAdapter(driverViewModel)
86 } 124 }
87 125
88 viewLifecycleOwner.lifecycleScope.apply {
89 launch {
90 driverViewModel.driverList.collectLatest {
91 (binding.listDrivers.adapter as DriverAdapter).submitList(it)
92 }
93 }
94 launch {
95 driverViewModel.newDriverInstalled.collect {
96 if (_binding != null && it) {
97 (binding.listDrivers.adapter as DriverAdapter).apply {
98 notifyItemChanged(driverViewModel.previouslySelectedDriver)
99 notifyItemChanged(driverViewModel.selectedDriver)
100 driverViewModel.setNewDriverInstalled(false)
101 }
102 }
103 }
104 }
105 }
106
107 setInsets() 126 setInsets()
108 } 127 }
109 128
@@ -160,7 +179,7 @@ class DriverManagerFragment : Fragment() {
160 false 179 false
161 ) { 180 ) {
162 val driverPath = 181 val driverPath =
163 "${GpuDriverHelper.driverStoragePath}/${FileUtil.getFilename(result)}" 182 "${GpuDriverHelper.driverStoragePath}${FileUtil.getFilename(result)}"
164 val driverFile = File(driverPath) 183 val driverFile = File(driverPath)
165 184
166 // Ignore file exceptions when a user selects an invalid zip 185 // Ignore file exceptions when a user selects an invalid zip
@@ -177,12 +196,21 @@ class DriverManagerFragment : Fragment() {
177 196
178 val driverData = GpuDriverHelper.getMetadataFromZip(driverFile) 197 val driverData = GpuDriverHelper.getMetadataFromZip(driverFile)
179 val driverInList = 198 val driverInList =
180 driverViewModel.driverList.value.firstOrNull { it.second == driverData } 199 driverViewModel.driverData.firstOrNull { it.second == driverData }
181 if (driverInList != null) { 200 if (driverInList != null) {
182 return@newInstance getString(R.string.driver_already_installed) 201 return@newInstance getString(R.string.driver_already_installed)
183 } else { 202 } else {
184 driverViewModel.addDriver(Pair(driverPath, driverData)) 203 driverViewModel.onDriverAdded(Pair(driverPath, driverData))
185 driverViewModel.setNewDriverInstalled(true) 204 withContext(Dispatchers.Main) {
205 if (_binding != null) {
206 val adapter = binding.listDrivers.adapter as DriverAdapter
207 adapter.addItem(driverData.toDriver())
208 adapter.selectItem(adapter.currentList.indices.last)
209 driverViewModel.showClearButton(!StringSetting.DRIVER_PATH.global)
210 binding.listDrivers
211 .smoothScrollToPosition(adapter.currentList.indices.last)
212 }
213 }
186 } 214 }
187 return@newInstance Any() 215 return@newInstance Any()
188 }.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG) 216 }.show(childFragmentManager, IndeterminateProgressDialogFragment.TAG)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt
new file mode 100644
index 000000000..de342212a
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Driver.kt
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.model
5
6import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
7
8data class Driver(
9 override var selected: Boolean,
10 val title: String,
11 val version: String = "",
12 val description: String = ""
13) : SelectableItem {
14 override fun onSelectionStateChanged(selected: Boolean) {
15 this.selected = selected
16 }
17
18 companion object {
19 fun GpuDriverMetadata.toDriver(selected: Boolean = false): Driver =
20 Driver(
21 selected,
22 this.name ?: "",
23 this.version ?: "",
24 this.description ?: ""
25 )
26 }
27}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
index 76accf8f3..15ae3a42b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/DriverViewModel.kt
@@ -9,6 +9,7 @@ import kotlinx.coroutines.Dispatchers
9import kotlinx.coroutines.flow.MutableStateFlow 9import kotlinx.coroutines.flow.MutableStateFlow
10import kotlinx.coroutines.flow.SharingStarted 10import kotlinx.coroutines.flow.SharingStarted
11import kotlinx.coroutines.flow.StateFlow 11import kotlinx.coroutines.flow.StateFlow
12import kotlinx.coroutines.flow.asStateFlow
12import kotlinx.coroutines.flow.combine 13import kotlinx.coroutines.flow.combine
13import kotlinx.coroutines.flow.stateIn 14import kotlinx.coroutines.flow.stateIn
14import kotlinx.coroutines.launch 15import kotlinx.coroutines.launch
@@ -17,11 +18,10 @@ import org.yuzu.yuzu_emu.R
17import org.yuzu.yuzu_emu.YuzuApplication 18import org.yuzu.yuzu_emu.YuzuApplication
18import org.yuzu.yuzu_emu.features.settings.model.StringSetting 19import org.yuzu.yuzu_emu.features.settings.model.StringSetting
19import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 20import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
20import org.yuzu.yuzu_emu.utils.FileUtil 21import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
21import org.yuzu.yuzu_emu.utils.GpuDriverHelper 22import org.yuzu.yuzu_emu.utils.GpuDriverHelper
22import org.yuzu.yuzu_emu.utils.GpuDriverMetadata 23import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
23import org.yuzu.yuzu_emu.utils.NativeConfig 24import org.yuzu.yuzu_emu.utils.NativeConfig
24import java.io.BufferedOutputStream
25import java.io.File 25import java.io.File
26 26
27class DriverViewModel : ViewModel() { 27class DriverViewModel : ViewModel() {
@@ -38,97 +38,81 @@ class DriverViewModel : ViewModel() {
38 !loading && ready && !deleting 38 !loading && ready && !deleting
39 }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false) 39 }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = false)
40 40
41 private val _driverList = MutableStateFlow(GpuDriverHelper.getDrivers()) 41 var driverData = GpuDriverHelper.getDrivers()
42 val driverList: StateFlow<MutableList<Pair<String, GpuDriverMetadata>>> get() = _driverList
43 42
44 var previouslySelectedDriver = 0 43 private val _driverList = MutableStateFlow(emptyList<Driver>())
45 var selectedDriver = -1 44 val driverList: StateFlow<List<Driver>> get() = _driverList
46 45
47 // Used for showing which driver is currently installed within the driver manager card 46 // Used for showing which driver is currently installed within the driver manager card
48 private val _selectedDriverTitle = MutableStateFlow("") 47 private val _selectedDriverTitle = MutableStateFlow("")
49 val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle 48 val selectedDriverTitle: StateFlow<String> get() = _selectedDriverTitle
50 49
51 private val _newDriverInstalled = MutableStateFlow(false) 50 private val _showClearButton = MutableStateFlow(false)
52 val newDriverInstalled: StateFlow<Boolean> get() = _newDriverInstalled 51 val showClearButton = _showClearButton.asStateFlow()
53 52
54 val driversToDelete = mutableListOf<String>() 53 private val driversToDelete = mutableListOf<String>()
55 54
56 init { 55 init {
57 val currentDriverMetadata = GpuDriverHelper.installedCustomDriverData 56 updateDriverList()
58 findSelectedDriver(currentDriverMetadata) 57 updateDriverNameForGame(null)
59 58 }
60 // If a user had installed a driver before the manager was implemented, this zips
61 // the installed driver to UserData/gpu_drivers/CustomDriver.zip so that it can
62 // be indexed and exported as expected.
63 if (selectedDriver == -1) {
64 val driverToSave =
65 File(GpuDriverHelper.driverStoragePath, "CustomDriver.zip")
66 driverToSave.createNewFile()
67 FileUtil.zipFromInternalStorage(
68 File(GpuDriverHelper.driverInstallationPath!!),
69 GpuDriverHelper.driverInstallationPath!!,
70 BufferedOutputStream(driverToSave.outputStream())
71 )
72 _driverList.value.add(Pair(driverToSave.path, currentDriverMetadata))
73 setSelectedDriverIndex(_driverList.value.size - 1)
74 }
75 59
76 // If a user had installed a driver before the config was reworked to be multiplatform, 60 fun reloadDriverData() {
77 // we have save the path of the previously selected driver to the new setting. 61 _areDriversLoading.value = true
78 if (StringSetting.DRIVER_PATH.getString(true).isEmpty() && selectedDriver > 0 && 62 driverData = GpuDriverHelper.getDrivers()
79 StringSetting.DRIVER_PATH.global 63 updateDriverList()
80 ) { 64 _areDriversLoading.value = false
81 StringSetting.DRIVER_PATH.setString(_driverList.value[selectedDriver].first) 65 }
82 NativeConfig.saveGlobalConfig() 66
83 } else { 67 fun updateDriverList() {
84 findSelectedDriver(GpuDriverHelper.customDriverSettingData) 68 val selectedDriver = GpuDriverHelper.customDriverSettingData
69 val newDriverList = mutableListOf(
70 Driver(
71 selectedDriver == GpuDriverMetadata(),
72 YuzuApplication.appContext.getString(R.string.system_gpu_driver)
73 )
74 )
75 driverData.forEach {
76 newDriverList.add(it.second.toDriver(it.second == selectedDriver))
85 } 77 }
86 updateDriverNameForGame(null) 78 _driverList.value = newDriverList
87 } 79 }
88 80
89 fun setSelectedDriverIndex(value: Int) { 81 fun onOpenDriverManager(game: Game?) {
90 if (selectedDriver != -1) { 82 if (game != null) {
91 previouslySelectedDriver = selectedDriver 83 SettingsFile.loadCustomConfig(game)
92 } 84 }
93 selectedDriver = value 85 updateDriverList()
94 } 86 }
95 87
96 fun setNewDriverInstalled(value: Boolean) { 88 fun showClearButton(value: Boolean) {
97 _newDriverInstalled.value = value 89 _showClearButton.value = value
98 } 90 }
99 91
100 fun addDriver(driverData: Pair<String, GpuDriverMetadata>) { 92 fun onDriverSelected(position: Int) {
101 val driverIndex = _driverList.value.indexOfFirst { it == driverData } 93 if (position == 0) {
102 if (driverIndex == -1) { 94 StringSetting.DRIVER_PATH.setString("")
103 _driverList.value.add(driverData)
104 setSelectedDriverIndex(_driverList.value.size - 1)
105 _selectedDriverTitle.value = driverData.second.name
106 ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
107 } else { 95 } else {
108 setSelectedDriverIndex(driverIndex) 96 StringSetting.DRIVER_PATH.setString(driverData[position - 1].first)
109 } 97 }
110 } 98 }
111 99
112 fun removeDriver(driverData: Pair<String, GpuDriverMetadata>) { 100 fun onDriverRemoved(removedPosition: Int, selectedPosition: Int) {
113 _driverList.value.remove(driverData) 101 driversToDelete.add(driverData[removedPosition - 1].first)
102 driverData.removeAt(removedPosition - 1)
103 onDriverSelected(selectedPosition)
114 } 104 }
115 105
116 fun onOpenDriverManager(game: Game?) { 106 fun onDriverAdded(driver: Pair<String, GpuDriverMetadata>) {
117 if (game != null) { 107 if (driversToDelete.contains(driver.first)) {
118 SettingsFile.loadCustomConfig(game) 108 driversToDelete.remove(driver.first)
119 }
120
121 val driverPath = StringSetting.DRIVER_PATH.getString()
122 if (driverPath.isEmpty()) {
123 setSelectedDriverIndex(0)
124 } else {
125 findSelectedDriver(GpuDriverHelper.getMetadataFromZip(File(driverPath)))
126 } 109 }
110 driverData.add(driver)
111 onDriverSelected(driverData.size)
127 } 112 }
128 113
129 fun onCloseDriverManager(game: Game?) { 114 fun onCloseDriverManager(game: Game?) {
130 _isDeletingDrivers.value = true 115 _isDeletingDrivers.value = true
131 StringSetting.DRIVER_PATH.setString(driverList.value[selectedDriver].first)
132 updateDriverNameForGame(game) 116 updateDriverNameForGame(game)
133 if (game == null) { 117 if (game == null) {
134 NativeConfig.saveGlobalConfig() 118 NativeConfig.saveGlobalConfig()
@@ -181,20 +165,6 @@ class DriverViewModel : ViewModel() {
181 } 165 }
182 } 166 }
183 167
184 private fun findSelectedDriver(currentDriverMetadata: GpuDriverMetadata) {
185 if (driverList.value.size == 1) {
186 setSelectedDriverIndex(0)
187 return
188 }
189
190 driverList.value.forEachIndexed { i: Int, driver: Pair<String, GpuDriverMetadata> ->
191 if (driver.second == currentDriverMetadata) {
192 setSelectedDriverIndex(i)
193 return
194 }
195 }
196 }
197
198 fun updateDriverNameForGame(game: Game?) { 168 fun updateDriverNameForGame(game: Game?) {
199 if (!GpuDriverHelper.supportsCustomDriverLoading()) { 169 if (!GpuDriverHelper.supportsCustomDriverLoading()) {
200 return 170 return
@@ -217,7 +187,6 @@ class DriverViewModel : ViewModel() {
217 187
218 private fun setDriverReady() { 188 private fun setDriverReady() {
219 _isDriverReady.value = true 189 _isDriverReady.value = true
220 _selectedDriverTitle.value = GpuDriverHelper.customDriverSettingData.name 190 updateName()
221 ?: YuzuApplication.appContext.getString(R.string.system_gpu_driver)
222 } 191 }
223} 192}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt
new file mode 100644
index 000000000..11c22d323
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SelectableItem.kt
@@ -0,0 +1,9 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.model
5
6interface SelectableItem {
7 var selected: Boolean
8 fun onSelectionStateChanged(selected: Boolean)
9}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 622ae996e..644289e25 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -41,6 +41,7 @@ import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment
41import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment 41import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
42import org.yuzu.yuzu_emu.fragments.MessageDialogFragment 42import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
43import org.yuzu.yuzu_emu.model.AddonViewModel 43import org.yuzu.yuzu_emu.model.AddonViewModel
44import org.yuzu.yuzu_emu.model.DriverViewModel
44import org.yuzu.yuzu_emu.model.GamesViewModel 45import org.yuzu.yuzu_emu.model.GamesViewModel
45import org.yuzu.yuzu_emu.model.HomeViewModel 46import org.yuzu.yuzu_emu.model.HomeViewModel
46import org.yuzu.yuzu_emu.model.TaskState 47import org.yuzu.yuzu_emu.model.TaskState
@@ -58,6 +59,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
58 private val gamesViewModel: GamesViewModel by viewModels() 59 private val gamesViewModel: GamesViewModel by viewModels()
59 private val taskViewModel: TaskViewModel by viewModels() 60 private val taskViewModel: TaskViewModel by viewModels()
60 private val addonViewModel: AddonViewModel by viewModels() 61 private val addonViewModel: AddonViewModel by viewModels()
62 private val driverViewModel: DriverViewModel by viewModels()
61 63
62 override var themeId: Int = 0 64 override var themeId: Int = 0
63 65
@@ -689,6 +691,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
689 NativeLibrary.initializeSystem(true) 691 NativeLibrary.initializeSystem(true)
690 NativeConfig.initializeGlobalConfig() 692 NativeConfig.initializeGlobalConfig()
691 gamesViewModel.reloadGames(false) 693 gamesViewModel.reloadGames(false)
694 driverViewModel.reloadDriverData()
692 695
693 return@newInstance getString(R.string.user_data_import_success) 696 return@newInstance getString(R.string.user_data_import_success)
694 }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG) 697 }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
index 685272288..a8f9dcc34 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
@@ -62,9 +62,6 @@ object GpuDriverHelper {
62 ?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name } 62 ?.sortedByDescending { it: Pair<String, GpuDriverMetadata> -> it.second.name }
63 ?.distinct() 63 ?.distinct()
64 ?.toMutableList() ?: mutableListOf() 64 ?.toMutableList() ?: mutableListOf()
65
66 // TODO: Get system driver information
67 drivers.add(0, Pair("", GpuDriverMetadata()))
68 return drivers 65 return drivers
69 } 66 }
70 67
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt
new file mode 100644
index 000000000..7101ad434
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/viewholder/AbstractViewHolder.kt
@@ -0,0 +1,18 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4package org.yuzu.yuzu_emu.viewholder
5
6import androidx.recyclerview.widget.RecyclerView
7import androidx.viewbinding.ViewBinding
8import org.yuzu.yuzu_emu.adapters.AbstractDiffAdapter
9import org.yuzu.yuzu_emu.adapters.AbstractListAdapter
10
11/**
12 * [RecyclerView.ViewHolder] meant to work together with a [AbstractDiffAdapter] or a
13 * [AbstractListAdapter] so we can run [bind] on each list item without needing a manual hookup.
14 */
15abstract class AbstractViewHolder<Model>(binding: ViewBinding) :
16 RecyclerView.ViewHolder(binding.root) {
17 abstract fun bind(model: Model)
18}
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 136c8dee6..e436622e0 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -410,8 +410,8 @@ void EmulationSession::OnGamepadConnectEvent([[maybe_unused]] int index) {
410 jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); 410 jauto handheld = m_system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
411 411
412 if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) { 412 if (controller->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::Handheld) {
413 handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); 413 handheld->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
414 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); 414 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
415 handheld->Disconnect(); 415 handheld->Disconnect();
416 } 416 }
417 } 417 }
diff --git a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
index a26ffbc73..655e49219 100644
--- a/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
+++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
@@ -147,7 +147,7 @@
147 android:layout_marginHorizontal="20dp" /> 147 android:layout_marginHorizontal="20dp" />
148 148
149 <LinearLayout 149 <LinearLayout
150 android:id="@+id/button_build_hash" 150 android:id="@+id/button_version_name"
151 android:layout_width="match_parent" 151 android:layout_width="match_parent"
152 android:layout_height="wrap_content" 152 android:layout_height="wrap_content"
153 android:background="?attr/selectableItemBackground" 153 android:background="?attr/selectableItemBackground"
@@ -164,7 +164,7 @@
164 android:textAlignment="viewStart" /> 164 android:textAlignment="viewStart" />
165 165
166 <com.google.android.material.textview.MaterialTextView 166 <com.google.android.material.textview.MaterialTextView
167 android:id="@+id/text_build_hash" 167 android:id="@+id/text_version_name"
168 style="@style/TextAppearance.Material3.BodyMedium" 168 style="@style/TextAppearance.Material3.BodyMedium"
169 android:layout_width="match_parent" 169 android:layout_width="match_parent"
170 android:layout_height="wrap_content" 170 android:layout_height="wrap_content"
diff --git a/src/android/app/src/main/res/layout/fragment_about.xml b/src/android/app/src/main/res/layout/fragment_about.xml
index a24f5230e..38090fa50 100644
--- a/src/android/app/src/main/res/layout/fragment_about.xml
+++ b/src/android/app/src/main/res/layout/fragment_about.xml
@@ -148,7 +148,7 @@
148 android:layout_marginHorizontal="20dp" /> 148 android:layout_marginHorizontal="20dp" />
149 149
150 <LinearLayout 150 <LinearLayout
151 android:id="@+id/button_build_hash" 151 android:id="@+id/button_version_name"
152 android:layout_width="match_parent" 152 android:layout_width="match_parent"
153 android:layout_height="wrap_content" 153 android:layout_height="wrap_content"
154 android:paddingVertical="16dp" 154 android:paddingVertical="16dp"
@@ -165,7 +165,7 @@
165 android:text="@string/build" /> 165 android:text="@string/build" />
166 166
167 <com.google.android.material.textview.MaterialTextView 167 <com.google.android.material.textview.MaterialTextView
168 android:id="@+id/text_build_hash" 168 android:id="@+id/text_version_name"
169 style="@style/TextAppearance.Material3.BodyMedium" 169 style="@style/TextAppearance.Material3.BodyMedium"
170 android:layout_width="match_parent" 170 android:layout_width="match_parent"
171 android:layout_height="wrap_content" 171 android:layout_height="wrap_content"
diff --git a/src/android/app/src/main/res/menu/menu_driver_manager.xml b/src/android/app/src/main/res/menu/menu_driver_manager.xml
new file mode 100644
index 000000000..dee5d57b6
--- /dev/null
+++ b/src/android/app/src/main/res/menu/menu_driver_manager.xml
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<menu xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto">
4
5 <item
6 android:id="@+id/menu_driver_clear"
7 android:icon="@drawable/ic_clear"
8 android:title="@string/clear"
9 app:showAsAction="always" />
10
11</menu>
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h
index 0deea9c58..a249dc5f7 100644
--- a/src/core/cpu_manager.h
+++ b/src/core/cpu_manager.h
@@ -64,7 +64,7 @@ public:
64 return [this] { ShutdownThreadFunction(); }; 64 return [this] { ShutdownThreadFunction(); };
65 } 65 }
66 66
67 void PreemptSingleCore(bool from_running_enviroment = true); 67 void PreemptSingleCore(bool from_running_environment = true);
68 68
69 std::size_t CurrentCore() const { 69 std::size_t CurrentCore() const {
70 return current_core.load(); 70 return current_core.load();
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index 66e46c4ba..4051ed4af 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -559,28 +559,28 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>&
559} 559}
560 560
561constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{ 561constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{
562 {"----- Free -----", Kernel::Svc::MemoryState::Free}, 562 {"----- Free ------", Kernel::Svc::MemoryState::Free},
563 {"Io ", Kernel::Svc::MemoryState::Io}, 563 {"Io ", Kernel::Svc::MemoryState::Io},
564 {"Static ", Kernel::Svc::MemoryState::Static}, 564 {"Static ", Kernel::Svc::MemoryState::Static},
565 {"Code ", Kernel::Svc::MemoryState::Code}, 565 {"Code ", Kernel::Svc::MemoryState::Code},
566 {"CodeData ", Kernel::Svc::MemoryState::CodeData}, 566 {"CodeData ", Kernel::Svc::MemoryState::CodeData},
567 {"Normal ", Kernel::Svc::MemoryState::Normal}, 567 {"Normal ", Kernel::Svc::MemoryState::Normal},
568 {"Shared ", Kernel::Svc::MemoryState::Shared}, 568 {"Shared ", Kernel::Svc::MemoryState::Shared},
569 {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, 569 {"AliasCode ", Kernel::Svc::MemoryState::AliasCode},
570 {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, 570 {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData},
571 {"Ipc ", Kernel::Svc::MemoryState::Ipc}, 571 {"Ipc ", Kernel::Svc::MemoryState::Ipc},
572 {"Stack ", Kernel::Svc::MemoryState::Stack}, 572 {"Stack ", Kernel::Svc::MemoryState::Stack},
573 {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, 573 {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal},
574 {"Transfered ", Kernel::Svc::MemoryState::Transfered}, 574 {"Transferred ", Kernel::Svc::MemoryState::Transferred},
575 {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered}, 575 {"SharedTransferred", Kernel::Svc::MemoryState::SharedTransferred},
576 {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, 576 {"SharedCode ", Kernel::Svc::MemoryState::SharedCode},
577 {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, 577 {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible},
578 {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, 578 {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc},
579 {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, 579 {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc},
580 {"Kernel ", Kernel::Svc::MemoryState::Kernel}, 580 {"Kernel ", Kernel::Svc::MemoryState::Kernel},
581 {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, 581 {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode},
582 {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, 582 {"CodeOut ", Kernel::Svc::MemoryState::CodeOut},
583 {"Coverage ", Kernel::Svc::MemoryState::Coverage}, 583 {"Coverage ", Kernel::Svc::MemoryState::Coverage},
584}}; 584}};
585 585
586static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { 586static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) {
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 34fe23b6a..e04d884ba 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -47,7 +47,7 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
47 // Connect controllers based on the following priority list from highest to lowest priority: 47 // Connect controllers based on the following priority list from highest to lowest priority:
48 // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld 48 // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
49 if (parameters.allow_pro_controller) { 49 if (parameters.allow_pro_controller) {
50 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); 50 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
51 controller->Connect(true); 51 controller->Connect(true);
52 } else if (parameters.allow_dual_joycons) { 52 } else if (parameters.allow_dual_joycons) {
53 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); 53 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h
index ef3f61321..d2b7e9a66 100644
--- a/src/core/hle/kernel/k_memory_block.h
+++ b/src/core/hle/kernel/k_memory_block.h
@@ -81,12 +81,12 @@ enum class KMemoryState : u32 {
81 81
82 ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped, 82 ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagLinearMapped,
83 83
84 Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc | 84 Transferred = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
85 FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | 85 FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
86 FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, 86 FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
87 87
88 SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc | 88 SharedTransferred = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
89 FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, 89 FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
90 90
91 SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped | 91 SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
92 FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc | 92 FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc |
@@ -130,8 +130,8 @@ static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x0FFFBD09);
130static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A); 130static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A);
131static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B); 131static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B);
132static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C); 132static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400000C);
133static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D); 133static_assert(static_cast<u32>(KMemoryState::Transferred) == 0x055C3C0D);
134static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E); 134static_assert(static_cast<u32>(KMemoryState::SharedTransferred) == 0x045C380E);
135static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F); 135static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F);
136static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010); 136static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
137static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811); 137static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811);
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp
index 8c1549559..73fbda331 100644
--- a/src/core/hle/kernel/k_page_table_base.cpp
+++ b/src/core/hle/kernel/k_page_table_base.cpp
@@ -486,8 +486,8 @@ KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const {
486 case Svc::MemoryState::Shared: 486 case Svc::MemoryState::Shared:
487 case Svc::MemoryState::AliasCode: 487 case Svc::MemoryState::AliasCode:
488 case Svc::MemoryState::AliasCodeData: 488 case Svc::MemoryState::AliasCodeData:
489 case Svc::MemoryState::Transfered: 489 case Svc::MemoryState::Transferred:
490 case Svc::MemoryState::SharedTransfered: 490 case Svc::MemoryState::SharedTransferred:
491 case Svc::MemoryState::SharedCode: 491 case Svc::MemoryState::SharedCode:
492 case Svc::MemoryState::GeneratedCode: 492 case Svc::MemoryState::GeneratedCode:
493 case Svc::MemoryState::CodeOut: 493 case Svc::MemoryState::CodeOut:
@@ -522,8 +522,8 @@ size_t KPageTableBase::GetRegionSize(Svc::MemoryState state) const {
522 case Svc::MemoryState::Shared: 522 case Svc::MemoryState::Shared:
523 case Svc::MemoryState::AliasCode: 523 case Svc::MemoryState::AliasCode:
524 case Svc::MemoryState::AliasCodeData: 524 case Svc::MemoryState::AliasCodeData:
525 case Svc::MemoryState::Transfered: 525 case Svc::MemoryState::Transferred:
526 case Svc::MemoryState::SharedTransfered: 526 case Svc::MemoryState::SharedTransferred:
527 case Svc::MemoryState::SharedCode: 527 case Svc::MemoryState::SharedCode:
528 case Svc::MemoryState::GeneratedCode: 528 case Svc::MemoryState::GeneratedCode:
529 case Svc::MemoryState::CodeOut: 529 case Svc::MemoryState::CodeOut:
@@ -564,8 +564,8 @@ bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, Svc::MemorySt
564 case Svc::MemoryState::AliasCodeData: 564 case Svc::MemoryState::AliasCodeData:
565 case Svc::MemoryState::Stack: 565 case Svc::MemoryState::Stack:
566 case Svc::MemoryState::ThreadLocal: 566 case Svc::MemoryState::ThreadLocal:
567 case Svc::MemoryState::Transfered: 567 case Svc::MemoryState::Transferred:
568 case Svc::MemoryState::SharedTransfered: 568 case Svc::MemoryState::SharedTransferred:
569 case Svc::MemoryState::SharedCode: 569 case Svc::MemoryState::SharedCode:
570 case Svc::MemoryState::GeneratedCode: 570 case Svc::MemoryState::GeneratedCode:
571 case Svc::MemoryState::CodeOut: 571 case Svc::MemoryState::CodeOut:
diff --git a/src/core/hle/kernel/k_transfer_memory.cpp b/src/core/hle/kernel/k_transfer_memory.cpp
index 0e2e11743..cbb1b02bb 100644
--- a/src/core/hle/kernel/k_transfer_memory.cpp
+++ b/src/core/hle/kernel/k_transfer_memory.cpp
@@ -76,8 +76,8 @@ Result KTransferMemory::Map(KProcessAddress address, size_t size, Svc::MemoryPer
76 76
77 // Map the memory. 77 // Map the memory.
78 const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) 78 const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
79 ? KMemoryState::Transfered 79 ? KMemoryState::Transferred
80 : KMemoryState::SharedTransfered; 80 : KMemoryState::SharedTransferred;
81 R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup( 81 R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup(
82 address, *m_page_group, state, KMemoryPermission::UserReadWrite)); 82 address, *m_page_group, state, KMemoryPermission::UserReadWrite));
83 83
@@ -96,8 +96,8 @@ Result KTransferMemory::Unmap(KProcessAddress address, size_t size) {
96 96
97 // Unmap the memory. 97 // Unmap the memory.
98 const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None) 98 const KMemoryState state = (m_owner_perm == Svc::MemoryPermission::None)
99 ? KMemoryState::Transfered 99 ? KMemoryState::Transferred
100 : KMemoryState::SharedTransfered; 100 : KMemoryState::SharedTransferred;
101 R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state)); 101 R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, state));
102 102
103 // Mark ourselves as unmapped. 103 // Mark ourselves as unmapped.
diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
index 1f97121b3..671bca23f 100644
--- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp
@@ -90,7 +90,7 @@ Result MapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t add
90 // Verify that the mapping is in range. 90 // Verify that the mapping is in range.
91 R_UNLESS(GetCurrentProcess(system.Kernel()) 91 R_UNLESS(GetCurrentProcess(system.Kernel())
92 .GetPageTable() 92 .GetPageTable()
93 .CanContain(address, size, KMemoryState::Transfered), 93 .CanContain(address, size, KMemoryState::Transferred),
94 ResultInvalidMemoryRegion); 94 ResultInvalidMemoryRegion);
95 95
96 // Map the transfer memory. 96 // Map the transfer memory.
@@ -117,7 +117,7 @@ Result UnmapTransferMemory(Core::System& system, Handle trmem_handle, uint64_t a
117 // Verify that the mapping is in range. 117 // Verify that the mapping is in range.
118 R_UNLESS(GetCurrentProcess(system.Kernel()) 118 R_UNLESS(GetCurrentProcess(system.Kernel())
119 .GetPageTable() 119 .GetPageTable()
120 .CanContain(address, size, KMemoryState::Transfered), 120 .CanContain(address, size, KMemoryState::Transferred),
121 ResultInvalidMemoryRegion); 121 ResultInvalidMemoryRegion);
122 122
123 // Unmap the transfer memory. 123 // Unmap the transfer memory.
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index 50de02e36..ab432ea78 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -27,8 +27,8 @@ enum class MemoryState : u32 {
27 Ipc = 0x0A, 27 Ipc = 0x0A,
28 Stack = 0x0B, 28 Stack = 0x0B,
29 ThreadLocal = 0x0C, 29 ThreadLocal = 0x0C,
30 Transfered = 0x0D, 30 Transferred = 0x0D,
31 SharedTransfered = 0x0E, 31 SharedTransferred = 0x0E,
32 SharedCode = 0x0F, 32 SharedCode = 0x0F,
33 Inaccessible = 0x10, 33 Inaccessible = 0x10,
34 NonSecureIpc = 0x11, 34 NonSecureIpc = 0x11,
diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h
index 369f9250f..673eed516 100644
--- a/src/core/hle/service/am/applets/applet_profile_select.h
+++ b/src/core/hle/service/am/applets/applet_profile_select.h
@@ -76,7 +76,7 @@ struct UiSettingsDisplayOptions {
76 bool is_system_or_launcher; 76 bool is_system_or_launcher;
77 bool is_registration_permitted; 77 bool is_registration_permitted;
78 bool show_skip_button; 78 bool show_skip_button;
79 bool aditional_select; 79 bool additional_select;
80 bool show_user_selector; 80 bool show_user_selector;
81 bool is_unqualified_user_selectable; 81 bool is_unqualified_user_selectable;
82}; 82};
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp
index 96b225d5f..261fc204c 100644
--- a/src/core/hle/service/caps/caps_manager.cpp
+++ b/src/core/hle/service/caps/caps_manager.cpp
@@ -85,7 +85,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<AlbumEntry>& out_entries, Albu
85} 85}
86 86
87Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, 87Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
88 ContentType contex_type, s64 start_posix_time, 88 ContentType content_type, s64 start_posix_time,
89 s64 end_posix_time, u64 aruid) const { 89 s64 end_posix_time, u64 aruid) const {
90 if (!is_mounted) { 90 if (!is_mounted) {
91 return ResultIsNotMounted; 91 return ResultIsNotMounted;
@@ -94,7 +94,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
94 std::vector<ApplicationAlbumEntry> album_entries; 94 std::vector<ApplicationAlbumEntry> album_entries;
95 const auto start_date = ConvertToAlbumDateTime(start_posix_time); 95 const auto start_date = ConvertToAlbumDateTime(start_posix_time);
96 const auto end_date = ConvertToAlbumDateTime(end_posix_time); 96 const auto end_date = ConvertToAlbumDateTime(end_posix_time);
97 const auto result = GetAlbumFileList(album_entries, contex_type, start_date, end_date, aruid); 97 const auto result = GetAlbumFileList(album_entries, content_type, start_date, end_date, aruid);
98 98
99 if (result.IsError()) { 99 if (result.IsError()) {
100 return result; 100 return result;
@@ -113,14 +113,14 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& ou
113} 113}
114 114
115Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, 115Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
116 ContentType contex_type, AlbumFileDateTime start_date, 116 ContentType content_type, AlbumFileDateTime start_date,
117 AlbumFileDateTime end_date, u64 aruid) const { 117 AlbumFileDateTime end_date, u64 aruid) const {
118 if (!is_mounted) { 118 if (!is_mounted) {
119 return ResultIsNotMounted; 119 return ResultIsNotMounted;
120 } 120 }
121 121
122 for (auto& [file_id, path] : album_files) { 122 for (auto& [file_id, path] : album_files) {
123 if (file_id.type != contex_type) { 123 if (file_id.type != content_type) {
124 continue; 124 continue;
125 } 125 }
126 if (file_id.date > start_date) { 126 if (file_id.date > start_date) {
@@ -139,7 +139,7 @@ Result AlbumManager::GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_en
139 .hash{}, 139 .hash{},
140 .datetime = file_id.date, 140 .datetime = file_id.date,
141 .storage = file_id.storage, 141 .storage = file_id.storage,
142 .content = contex_type, 142 .content = content_type,
143 .unknown = 1, 143 .unknown = 1,
144 }; 144 };
145 out_entries.push_back(entry); 145 out_entries.push_back(entry);
diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h
index e20c70c7b..6fd34f589 100644
--- a/src/core/hle/service/caps/caps_manager.h
+++ b/src/core/hle/service/caps/caps_manager.h
@@ -45,10 +45,10 @@ public:
45 Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage, 45 Result GetAlbumFileList(std::vector<AlbumEntry>& out_entries, AlbumStorage storage,
46 u8 flags) const; 46 u8 flags) const;
47 Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries, 47 Result GetAlbumFileList(std::vector<ApplicationAlbumFileEntry>& out_entries,
48 ContentType contex_type, s64 start_posix_time, s64 end_posix_time, 48 ContentType content_type, s64 start_posix_time, s64 end_posix_time,
49 u64 aruid) const; 49 u64 aruid) const;
50 Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries, 50 Result GetAlbumFileList(std::vector<ApplicationAlbumEntry>& out_entries,
51 ContentType contex_type, AlbumFileDateTime start_date, 51 ContentType content_type, AlbumFileDateTime start_date,
52 AlbumFileDateTime end_date, u64 aruid) const; 52 AlbumFileDateTime end_date, u64 aruid) const;
53 Result GetAutoSavingStorage(bool& out_is_autosaving) const; 53 Result GetAutoSavingStorage(bool& out_is_autosaving) const;
54 Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output, 54 Result LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& out_image_output,
diff --git a/src/core/hle/service/caps/caps_result.h b/src/core/hle/service/caps/caps_result.h
index c65e5fb9a..179ae4840 100644
--- a/src/core/hle/service/caps/caps_result.h
+++ b/src/core/hle/service/caps/caps_result.h
@@ -12,7 +12,7 @@ constexpr Result ResultUnknown5(ErrorModule::Capture, 5);
12constexpr Result ResultUnknown6(ErrorModule::Capture, 6); 12constexpr Result ResultUnknown6(ErrorModule::Capture, 6);
13constexpr Result ResultUnknown7(ErrorModule::Capture, 7); 13constexpr Result ResultUnknown7(ErrorModule::Capture, 7);
14constexpr Result ResultOutOfRange(ErrorModule::Capture, 8); 14constexpr Result ResultOutOfRange(ErrorModule::Capture, 8);
15constexpr Result ResulInvalidTimestamp(ErrorModule::Capture, 12); 15constexpr Result ResultInvalidTimestamp(ErrorModule::Capture, 12);
16constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13); 16constexpr Result ResultInvalidStorage(ErrorModule::Capture, 13);
17constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14); 17constexpr Result ResultInvalidFileContents(ErrorModule::Capture, 14);
18constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21); 18constexpr Result ResultIsNotMounted(ErrorModule::Capture, 21);
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index 0507b14e7..aeb849efa 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -131,7 +131,7 @@ private:
131 u8 is_favorite; 131 u8 is_favorite;
132 u8 same_app; 132 u8 same_app;
133 u8 same_app_played; 133 u8 same_app_played;
134 u8 arbitary_app_played; 134 u8 arbitrary_app_played;
135 u64 group_id; 135 u64 group_id;
136 }; 136 };
137 static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); 137 static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size");
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index fc8a3ab66..fc03a0a5f 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -18,23 +18,23 @@ namespace Service::HID {
18 18
19void LoopProcess(Core::System& system) { 19void LoopProcess(Core::System& system) {
20 auto server_manager = std::make_unique<ServerManager>(system); 20 auto server_manager = std::make_unique<ServerManager>(system);
21 std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system); 21 std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system);
22 std::shared_ptr<HidFirmwareSettings> firmware_settings = 22 std::shared_ptr<HidFirmwareSettings> firmware_settings =
23 std::make_shared<HidFirmwareSettings>(); 23 std::make_shared<HidFirmwareSettings>();
24 24
25 // TODO: Remove this hack until this service is emulated properly. 25 // TODO: Remove this hack until this service is emulated properly.
26 const auto process_list = system.Kernel().GetProcessList(); 26 const auto process_list = system.Kernel().GetProcessList();
27 if (!process_list.empty()) { 27 if (!process_list.empty()) {
28 resouce_manager->Initialize(); 28 resource_manager->Initialize();
29 resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); 29 resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
30 } 30 }
31 31
32 server_manager->RegisterNamedService( 32 server_manager->RegisterNamedService(
33 "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); 33 "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));
34 server_manager->RegisterNamedService( 34 server_manager->RegisterNamedService(
35 "hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager)); 35 "hid:dbg", std::make_shared<IHidDebugServer>(system, resource_manager));
36 server_manager->RegisterNamedService( 36 server_manager->RegisterNamedService(
37 "hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager)); 37 "hid:sys", std::make_shared<IHidSystemServer>(system, resource_manager));
38 38
39 server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); 39 server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system));
40 40
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index 74898888a..1951da33b 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -1498,7 +1498,7 @@ void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
1498 bool check_device_index = false; 1498 bool check_device_index = false;
1499 1499
1500 switch (vibration_device_handle.npad_type) { 1500 switch (vibration_device_handle.npad_type) {
1501 case Core::HID::NpadStyleIndex::ProController: 1501 case Core::HID::NpadStyleIndex::Fullkey:
1502 case Core::HID::NpadStyleIndex::Handheld: 1502 case Core::HID::NpadStyleIndex::Handheld:
1503 case Core::HID::NpadStyleIndex::JoyconDual: 1503 case Core::HID::NpadStyleIndex::JoyconDual:
1504 case Core::HID::NpadStyleIndex::JoyconLeft: 1504 case Core::HID::NpadStyleIndex::JoyconLeft:
diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp
index 46f503d38..c903ee8b8 100644
--- a/src/core/hle/service/hid/hidbus.cpp
+++ b/src/core/hle/service/hid/hidbus.cpp
@@ -67,7 +67,7 @@ HidBus::~HidBus() {
67void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) { 67void HidBus::UpdateHidbus(std::chrono::nanoseconds ns_late) {
68 if (is_hidbus_enabled) { 68 if (is_hidbus_enabled) {
69 for (std::size_t i = 0; i < devices.size(); ++i) { 69 for (std::size_t i = 0; i < devices.size(); ++i) {
70 if (!devices[i].is_device_initializated) { 70 if (!devices[i].is_device_initialized) {
71 continue; 71 continue;
72 } 72 }
73 auto& device = devices[i].device; 73 auto& device = devices[i].device;
@@ -213,7 +213,7 @@ void HidBus::Initialize(HLERequestContext& ctx) {
213 213
214 if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { 214 if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) {
215 MakeDevice<RingController>(bus_handle_); 215 MakeDevice<RingController>(bus_handle_);
216 devices[device_index.value()].is_device_initializated = true; 216 devices[device_index.value()].is_device_initialized = true;
217 devices[device_index.value()].device->ActivateDevice(); 217 devices[device_index.value()].device->ActivateDevice();
218 cur_entry.is_in_focus = true; 218 cur_entry.is_in_focus = true;
219 cur_entry.is_connected = true; 219 cur_entry.is_connected = true;
@@ -222,7 +222,7 @@ void HidBus::Initialize(HLERequestContext& ctx) {
222 cur_entry.is_polling_mode = false; 222 cur_entry.is_polling_mode = false;
223 } else { 223 } else {
224 MakeDevice<HidbusStubbed>(bus_handle_); 224 MakeDevice<HidbusStubbed>(bus_handle_);
225 devices[device_index.value()].is_device_initializated = true; 225 devices[device_index.value()].is_device_initialized = true;
226 cur_entry.is_in_focus = true; 226 cur_entry.is_in_focus = true;
227 cur_entry.is_connected = false; 227 cur_entry.is_connected = false;
228 cur_entry.is_connected_result = ResultSuccess; 228 cur_entry.is_connected_result = ResultSuccess;
@@ -261,7 +261,7 @@ void HidBus::Finalize(HLERequestContext& ctx) {
261 const auto entry_index = devices[device_index.value()].handle.internal_index; 261 const auto entry_index = devices[device_index.value()].handle.internal_index;
262 auto& cur_entry = hidbus_status.entries[entry_index]; 262 auto& cur_entry = hidbus_status.entries[entry_index];
263 auto& device = devices[device_index.value()].device; 263 auto& device = devices[device_index.value()].device;
264 devices[device_index.value()].is_device_initializated = false; 264 devices[device_index.value()].is_device_initialized = false;
265 device->DeactivateDevice(); 265 device->DeactivateDevice();
266 266
267 cur_entry.is_in_focus = true; 267 cur_entry.is_in_focus = true;
diff --git a/src/core/hle/service/hid/hidbus.h b/src/core/hle/service/hid/hidbus.h
index 05f62f634..03d9f6863 100644
--- a/src/core/hle/service/hid/hidbus.h
+++ b/src/core/hle/service/hid/hidbus.h
@@ -89,7 +89,7 @@ private:
89 static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size"); 89 static_assert(sizeof(HidbusStatusManager) <= 0x1000, "HidbusStatusManager is an invalid size");
90 90
91 struct HidbusDevice { 91 struct HidbusDevice {
92 bool is_device_initializated{}; 92 bool is_device_initialized{};
93 BusHandle handle{}; 93 BusHandle handle{};
94 std::unique_ptr<HidbusBase> device{nullptr}; 94 std::unique_ptr<HidbusBase> device{nullptr};
95 }; 95 };
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp
index 39df77e43..3f38ceb03 100644
--- a/src/core/hle/service/hle_ipc.cpp
+++ b/src/core/hle/service/hle_ipc.cpp
@@ -181,22 +181,22 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
181 } 181 }
182 } 182 }
183 183
184 buffer_x_desciptors.reserve(command_header->num_buf_x_descriptors); 184 buffer_x_descriptors.reserve(command_header->num_buf_x_descriptors);
185 buffer_a_desciptors.reserve(command_header->num_buf_a_descriptors); 185 buffer_a_descriptors.reserve(command_header->num_buf_a_descriptors);
186 buffer_b_desciptors.reserve(command_header->num_buf_b_descriptors); 186 buffer_b_descriptors.reserve(command_header->num_buf_b_descriptors);
187 buffer_w_desciptors.reserve(command_header->num_buf_w_descriptors); 187 buffer_w_descriptors.reserve(command_header->num_buf_w_descriptors);
188 188
189 for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { 189 for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) {
190 buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); 190 buffer_x_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>());
191 } 191 }
192 for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { 192 for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) {
193 buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 193 buffer_a_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
194 } 194 }
195 for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { 195 for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) {
196 buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 196 buffer_b_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
197 } 197 }
198 for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { 198 for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) {
199 buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); 199 buffer_w_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>());
200 } 200 }
201 201
202 const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size; 202 const auto buffer_c_offset = rp.GetCurrentOffset() + command_header->data_size;
@@ -246,7 +246,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
246 IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) { 246 IPC::CommandHeader::BufferDescriptorCFlag::InlineDescriptor) {
247 if (command_header->buf_c_descriptor_flags == 247 if (command_header->buf_c_descriptor_flags ==
248 IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { 248 IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) {
249 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); 249 buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
250 } else { 250 } else {
251 u32 num_buf_c_descriptors = 251 u32 num_buf_c_descriptors =
252 static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; 252 static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2;
@@ -256,7 +256,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
256 ASSERT(num_buf_c_descriptors < 14); 256 ASSERT(num_buf_c_descriptors < 14);
257 257
258 for (u32 i = 0; i < num_buf_c_descriptors; ++i) { 258 for (u32 i = 0; i < num_buf_c_descriptors; ++i) {
259 buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); 259 buffer_c_descriptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>());
260 } 260 }
261 } 261 }
262 } 262 }
diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h
index 40d86943e..440737db5 100644
--- a/src/core/hle/service/hle_ipc.h
+++ b/src/core/hle/service/hle_ipc.h
@@ -232,19 +232,19 @@ public:
232 } 232 }
233 233
234 [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { 234 [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const {
235 return buffer_x_desciptors; 235 return buffer_x_descriptors;
236 } 236 }
237 237
238 [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { 238 [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const {
239 return buffer_a_desciptors; 239 return buffer_a_descriptors;
240 } 240 }
241 241
242 [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { 242 [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const {
243 return buffer_b_desciptors; 243 return buffer_b_descriptors;
244 } 244 }
245 245
246 [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { 246 [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const {
247 return buffer_c_desciptors; 247 return buffer_c_descriptors;
248 } 248 }
249 249
250 [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { 250 [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const {
@@ -406,11 +406,11 @@ private:
406 std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; 406 std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header;
407 std::optional<IPC::DataPayloadHeader> data_payload_header; 407 std::optional<IPC::DataPayloadHeader> data_payload_header;
408 std::optional<IPC::DomainMessageHeader> domain_message_header; 408 std::optional<IPC::DomainMessageHeader> domain_message_header;
409 std::vector<IPC::BufferDescriptorX> buffer_x_desciptors; 409 std::vector<IPC::BufferDescriptorX> buffer_x_descriptors;
410 std::vector<IPC::BufferDescriptorABW> buffer_a_desciptors; 410 std::vector<IPC::BufferDescriptorABW> buffer_a_descriptors;
411 std::vector<IPC::BufferDescriptorABW> buffer_b_desciptors; 411 std::vector<IPC::BufferDescriptorABW> buffer_b_descriptors;
412 std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; 412 std::vector<IPC::BufferDescriptorABW> buffer_w_descriptors;
413 std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; 413 std::vector<IPC::BufferDescriptorC> buffer_c_descriptors;
414 414
415 u32_le command{}; 415 u32_le command{};
416 u64 pid{}; 416 u64 pid{};
diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
index 9556e9193..4274a92c9 100644
--- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp
+++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp
@@ -19,7 +19,7 @@ namespace Service::NFP::AmiiboCrypto {
19bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) { 19bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
20 const auto& amiibo_data = ntag_file.user_memory; 20 const auto& amiibo_data = ntag_file.user_memory;
21 LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock); 21 LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", ntag_file.static_lock);
22 LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", ntag_file.compability_container); 22 LOG_DEBUG(Service_NFP, "compatibility_container=0x{0:x}", ntag_file.compatibility_container);
23 LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter)); 23 LOG_DEBUG(Service_NFP, "write_count={}", static_cast<u16>(amiibo_data.write_counter));
24 24
25 LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); 25 LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id);
@@ -49,7 +49,7 @@ bool IsAmiiboValid(const EncryptedNTAG215File& ntag_file) {
49 if (ntag_file.static_lock != 0xE00F) { 49 if (ntag_file.static_lock != 0xE00F) {
50 return false; 50 return false;
51 } 51 }
52 if (ntag_file.compability_container != 0xEEFF10F1U) { 52 if (ntag_file.compatibility_container != 0xEEFF10F1U) {
53 return false; 53 return false;
54 } 54 }
55 if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) { 55 if (amiibo_data.model_info.tag_type != NFC::PackedTagType::Type2) {
@@ -78,7 +78,7 @@ NTAG215File NfcDataToEncodedData(const EncryptedNTAG215File& nfc_data) {
78 encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2; 78 encoded_data.uid_crc_check2 = nfc_data.uuid_crc_check2;
79 encoded_data.internal_number = nfc_data.internal_number; 79 encoded_data.internal_number = nfc_data.internal_number;
80 encoded_data.static_lock = nfc_data.static_lock; 80 encoded_data.static_lock = nfc_data.static_lock;
81 encoded_data.compability_container = nfc_data.compability_container; 81 encoded_data.compatibility_container = nfc_data.compatibility_container;
82 encoded_data.hmac_data = nfc_data.user_memory.hmac_data; 82 encoded_data.hmac_data = nfc_data.user_memory.hmac_data;
83 encoded_data.constant_value = nfc_data.user_memory.constant_value; 83 encoded_data.constant_value = nfc_data.user_memory.constant_value;
84 encoded_data.write_counter = nfc_data.user_memory.write_counter; 84 encoded_data.write_counter = nfc_data.user_memory.write_counter;
@@ -112,7 +112,7 @@ EncryptedNTAG215File EncodedDataToNfcData(const NTAG215File& encoded_data) {
112 nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2; 112 nfc_data.uuid_crc_check2 = encoded_data.uid_crc_check2;
113 nfc_data.internal_number = encoded_data.internal_number; 113 nfc_data.internal_number = encoded_data.internal_number;
114 nfc_data.static_lock = encoded_data.static_lock; 114 nfc_data.static_lock = encoded_data.static_lock;
115 nfc_data.compability_container = encoded_data.compability_container; 115 nfc_data.compatibility_container = encoded_data.compatibility_container;
116 nfc_data.user_memory.hmac_data = encoded_data.hmac_data; 116 nfc_data.user_memory.hmac_data = encoded_data.hmac_data;
117 nfc_data.user_memory.constant_value = encoded_data.constant_value; 117 nfc_data.user_memory.constant_value = encoded_data.constant_value;
118 nfc_data.user_memory.write_counter = encoded_data.write_counter; 118 nfc_data.user_memory.write_counter = encoded_data.write_counter;
@@ -257,7 +257,7 @@ void Cipher(const DerivedKeys& keys, const NTAG215File& in_data, NTAG215File& ou
257 out_data.uid_crc_check2 = in_data.uid_crc_check2; 257 out_data.uid_crc_check2 = in_data.uid_crc_check2;
258 out_data.internal_number = in_data.internal_number; 258 out_data.internal_number = in_data.internal_number;
259 out_data.static_lock = in_data.static_lock; 259 out_data.static_lock = in_data.static_lock;
260 out_data.compability_container = in_data.compability_container; 260 out_data.compatibility_container = in_data.compatibility_container;
261 261
262 out_data.constant_value = in_data.constant_value; 262 out_data.constant_value = in_data.constant_value;
263 out_data.write_counter = in_data.write_counter; 263 out_data.write_counter = in_data.write_counter;
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index b37fb6da3..31cc87acc 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -75,7 +75,7 @@ void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
75 return; 75 return;
76 } 76 }
77 77
78 if (!is_initalized) { 78 if (!is_initialized) {
79 return; 79 return;
80 } 80 }
81 81
@@ -207,7 +207,7 @@ void NfcDevice::Initialize() {
207 return; 207 return;
208 } 208 }
209 209
210 is_initalized = npad_device->AddNfcHandle(); 210 is_initialized = npad_device->AddNfcHandle();
211} 211}
212 212
213void NfcDevice::Finalize() { 213void NfcDevice::Finalize() {
@@ -226,7 +226,7 @@ void NfcDevice::Finalize() {
226 } 226 }
227 227
228 device_state = DeviceState::Unavailable; 228 device_state = DeviceState::Unavailable;
229 is_initalized = false; 229 is_initialized = false;
230} 230}
231 231
232Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) { 232Result NfcDevice::StartDetection(NfcProtocol allowed_protocol) {
diff --git a/src/core/hle/service/nfc/common/device.h b/src/core/hle/service/nfc/common/device.h
index d8efe25ec..15f9b25da 100644
--- a/src/core/hle/service/nfc/common/device.h
+++ b/src/core/hle/service/nfc/common/device.h
@@ -126,7 +126,7 @@ private:
126 Kernel::KEvent* deactivate_event = nullptr; 126 Kernel::KEvent* deactivate_event = nullptr;
127 Kernel::KEvent* availability_change_event = nullptr; 127 Kernel::KEvent* availability_change_event = nullptr;
128 128
129 bool is_initalized{}; 129 bool is_initialized{};
130 NfcProtocol allowed_protocols{}; 130 NfcProtocol allowed_protocols{};
131 DeviceState device_state{DeviceState::Unavailable}; 131 DeviceState device_state{DeviceState::Unavailable};
132 132
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index f96d21220..2505eb551 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -243,12 +243,12 @@ static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid si
243struct NTAG215File { 243struct NTAG215File {
244 u8 uid_crc_check2; 244 u8 uid_crc_check2;
245 u8 internal_number; 245 u8 internal_number;
246 u16 static_lock; // Set defined pages as read only 246 u16 static_lock; // Set defined pages as read only
247 u32 compability_container; // Defines available memory 247 u32 compatibility_container; // Defines available memory
248 HashData hmac_data; // Hash 248 HashData hmac_data; // Hash
249 u8 constant_value; // Must be A5 249 u8 constant_value; // Must be A5
250 u16_be write_counter; // Number of times the amiibo has been written? 250 u16_be write_counter; // Number of times the amiibo has been written?
251 u8 amiibo_version; // Amiibo file version 251 u8 amiibo_version; // Amiibo file version
252 AmiiboSettings settings; 252 AmiiboSettings settings;
253 Service::Mii::Ver3StoreData owner_mii; // Mii data 253 Service::Mii::Ver3StoreData owner_mii; // Mii data
254 u64_be application_id; // Game id 254 u64_be application_id; // Game id
@@ -278,7 +278,7 @@ struct EncryptedNTAG215File {
278 u8 uuid_crc_check2; 278 u8 uuid_crc_check2;
279 u8 internal_number; 279 u8 internal_number;
280 u16 static_lock; // Set defined pages as read only 280 u16 static_lock; // Set defined pages as read only
281 u32 compability_container; // Defines available memory 281 u32 compatibility_container; // Defines available memory
282 EncryptedAmiiboFile user_memory; // Writable data 282 EncryptedAmiiboFile user_memory; // Writable data
283 u32 dynamic_lock; // Dynamic lock 283 u32 dynamic_lock; // Dynamic lock
284 u32 CFG0; // Defines memory protected by password 284 u32 CFG0; // Defines memory protected by password
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 932997e75..79a21683d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -90,7 +90,7 @@ private:
90 u64_le align; 90 u64_le align;
91 }; 91 };
92 }; 92 };
93 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); 93 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitializeEx is incorrect size");
94 94
95 struct IoctlFreeSpace { 95 struct IoctlFreeSpace {
96 u64_le offset{}; 96 u64_le offset{};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 61a2df121..3e0c96456 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -15,7 +15,7 @@ namespace Service::Nvidia::Devices {
15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) 15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_)
16 : nvdevice{system_}, events_interface{events_interface_} { 16 : nvdevice{system_}, events_interface{events_interface_} {
17 error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); 17 error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier");
18 unknown_event = events_interface.CreateEvent("CtrlGpuUknownEvent"); 18 unknown_event = events_interface.CreateEvent("CtrlGpuUnknownEvent");
19} 19}
20nvhost_ctrl_gpu::~nvhost_ctrl_gpu() { 20nvhost_ctrl_gpu::~nvhost_ctrl_gpu() {
21 events_interface.FreeEvent(error_notifier_event); 21 events_interface.FreeEvent(error_notifier_event);
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h
index 0e2f47075..38f35e79f 100644
--- a/src/core/hle/service/nvdrv/nvdata.h
+++ b/src/core/hle/service/nvdrv/nvdata.h
@@ -51,7 +51,7 @@ enum class NvResult : u32 {
51 DispNoDisplaysAttached = 0x20003, 51 DispNoDisplaysAttached = 0x20003,
52 DispModeNotSupported = 0x20004, 52 DispModeNotSupported = 0x20004,
53 DispNotFound = 0x20005, 53 DispNotFound = 0x20005,
54 DispAttachDissallowed = 0x20006, 54 DispAttachDisallowed = 0x20006,
55 DispTypeNotSupported = 0x20007, 55 DispTypeNotSupported = 0x20007,
56 DispAuthenticationFailed = 0x20008, 56 DispAuthenticationFailed = 0x20008,
57 DispNotAttached = 0x20009, 57 DispNotAttached = 0x20009,
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index aa8aaa2d9..0469110e8 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -223,7 +223,8 @@ Result Nvnflinger::FindVsyncEvent(Kernel::KReadableEvent** out_vsync_event, u64
223 return VI::ResultNotFound; 223 return VI::ResultNotFound;
224 } 224 }
225 225
226 return display->GetVSyncEvent(out_vsync_event); 226 *out_vsync_event = display->GetVSyncEvent();
227 return ResultSuccess;
227} 228}
228 229
229VI::Display* Nvnflinger::FindDisplay(u64 display_id) { 230VI::Display* Nvnflinger::FindDisplay(u64 display_id) {
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp
index c13ffa6f6..3d0f2aeb7 100644
--- a/src/core/hle/service/pcv/pcv.cpp
+++ b/src/core/hle/service/pcv/pcv.cpp
@@ -54,8 +54,8 @@ public:
54 54
55class IClkrstSession final : public ServiceFramework<IClkrstSession> { 55class IClkrstSession final : public ServiceFramework<IClkrstSession> {
56public: 56public:
57 explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_) 57 explicit IClkrstSession(Core::System& system_, DeviceCode device_code_)
58 : ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) { 58 : ServiceFramework{system_, "IClkrstSession"}, device_code(device_code_) {
59 // clang-format off 59 // clang-format off
60 static const FunctionInfo functions[] = { 60 static const FunctionInfo functions[] = {
61 {0, nullptr, "SetClockEnabled"}, 61 {0, nullptr, "SetClockEnabled"},
@@ -93,7 +93,7 @@ private:
93 rb.Push<u32>(clock_rate); 93 rb.Push<u32>(clock_rate);
94 } 94 }
95 95
96 DeviceCode deivce_code; 96 DeviceCode device_code;
97 u32 clock_rate{}; 97 u32 clock_rate{};
98}; 98};
99 99
@@ -118,9 +118,9 @@ private:
118 void OpenSession(HLERequestContext& ctx) { 118 void OpenSession(HLERequestContext& ctx) {
119 IPC::RequestParser rp{ctx}; 119 IPC::RequestParser rp{ctx};
120 const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>()); 120 const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>());
121 const auto unkonwn_input = rp.Pop<u32>(); 121 const auto unknown_input = rp.Pop<u32>();
122 122
123 LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input); 123 LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unknown_input);
124 124
125 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 125 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
126 rb.Push(ResultSuccess); 126 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/set/system_settings.cpp b/src/core/hle/service/set/system_settings.cpp
index 2723417ad..5977429b2 100644
--- a/src/core/hle/service/set/system_settings.cpp
+++ b/src/core/hle/service/set/system_settings.cpp
@@ -28,7 +28,7 @@ SystemSettings DefaultSystemSettings() {
28 .cmu_mode = CmuMode::None, 28 .cmu_mode = CmuMode::None,
29 .tv_underscan = {}, 29 .tv_underscan = {},
30 .tv_gama = 1.0f, 30 .tv_gama = 1.0f,
31 .constrast_ratio = 0.5f, 31 .contrast_ratio = 0.5f,
32 }; 32 };
33 33
34 settings.initial_launch_settings_packed = { 34 settings.initial_launch_settings_packed = {
diff --git a/src/core/hle/service/set/system_settings.h b/src/core/hle/service/set/system_settings.h
index ded2906ad..6ec9e71e7 100644
--- a/src/core/hle/service/set/system_settings.h
+++ b/src/core/hle/service/set/system_settings.h
@@ -208,7 +208,7 @@ struct TvSettings {
208 CmuMode cmu_mode; 208 CmuMode cmu_mode;
209 u32 tv_underscan; 209 u32 tv_underscan;
210 f32 tv_gama; 210 f32 tv_gama;
211 f32 constrast_ratio; 211 f32 contrast_ratio;
212}; 212};
213static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); 213static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
214 214
@@ -341,7 +341,7 @@ struct SystemSettings {
341 std::array<u8, 0x3C> reserved_09934; 341 std::array<u8, 0x3C> reserved_09934;
342 342
343 // nn::settings::system::ErrorReportSharePermission 343 // nn::settings::system::ErrorReportSharePermission
344 ErrorReportSharePermission error_report_share_permssion; 344 ErrorReportSharePermission error_report_share_permission;
345 345
346 std::array<u8, 0x3C> reserved_09974; 346 std::array<u8, 0x3C> reserved_09974;
347 347
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index f7ad6193e..af9348522 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -721,10 +721,10 @@ void ISystemSettingsServer::SetTvSettings(HLERequestContext& ctx) {
721 SetSaveNeeded(); 721 SetSaveNeeded();
722 722
723 LOG_INFO(Service_SET, 723 LOG_INFO(Service_SET,
724 "called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, " 724 "called, flags={}, cmu_mode={}, contrast_ratio={}, hdmi_content_type={}, "
725 "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", 725 "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}",
726 m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, 726 m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode,
727 m_system_settings.tv_settings.constrast_ratio, 727 m_system_settings.tv_settings.contrast_ratio,
728 m_system_settings.tv_settings.hdmi_content_type, 728 m_system_settings.tv_settings.hdmi_content_type,
729 m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, 729 m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama,
730 m_system_settings.tv_settings.tv_resolution, 730 m_system_settings.tv_settings.tv_resolution,
@@ -870,10 +870,10 @@ void ISystemSettingsServer::GetInitialLaunchSettings(HLERequestContext& ctx) {
870 870
871void ISystemSettingsServer::SetInitialLaunchSettings(HLERequestContext& ctx) { 871void ISystemSettingsServer::SetInitialLaunchSettings(HLERequestContext& ctx) {
872 IPC::RequestParser rp{ctx}; 872 IPC::RequestParser rp{ctx};
873 auto inital_launch_settings = rp.PopRaw<InitialLaunchSettings>(); 873 auto initial_launch_settings = rp.PopRaw<InitialLaunchSettings>();
874 874
875 m_system_settings.initial_launch_settings_packed.flags = inital_launch_settings.flags; 875 m_system_settings.initial_launch_settings_packed.flags = initial_launch_settings.flags;
876 m_system_settings.initial_launch_settings_packed.timestamp = inital_launch_settings.timestamp; 876 m_system_settings.initial_launch_settings_packed.timestamp = initial_launch_settings.timestamp;
877 SetSaveNeeded(); 877 SetSaveNeeded();
878 878
879 LOG_INFO(Service_SET, "called, flags={}, timestamp={}", 879 LOG_INFO(Service_SET, "called, flags={}, timestamp={}",
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index 71ce9be50..e2d9cd98a 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -71,18 +71,7 @@ size_t Display::GetNumLayers() const {
71 return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); 71 return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); });
72} 72}
73 73
74Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) { 74Kernel::KReadableEvent* Display::GetVSyncEvent() {
75 if (got_vsync_event) {
76 return ResultPermissionDenied;
77 }
78
79 got_vsync_event = true;
80
81 *out_vsync_event = GetVSyncEventUnchecked();
82 return ResultSuccess;
83}
84
85Kernel::KReadableEvent* Display::GetVSyncEventUnchecked() {
86 return &vsync_event->GetReadableEvent(); 75 return &vsync_event->GetReadableEvent();
87} 76}
88 77
diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h
index 1d9360b96..7e68ee79b 100644
--- a/src/core/hle/service/vi/display/vi_display.h
+++ b/src/core/hle/service/vi/display/vi_display.h
@@ -74,16 +74,8 @@ public:
74 74
75 std::size_t GetNumLayers() const; 75 std::size_t GetNumLayers() const;
76 76
77 /**
78 * Gets the internal vsync event.
79 *
80 * @returns The internal Vsync event if it has not yet been retrieved,
81 * VI::ResultPermissionDenied otherwise.
82 */
83 [[nodiscard]] Result GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event);
84
85 /// Gets the internal vsync event. 77 /// Gets the internal vsync event.
86 Kernel::KReadableEvent* GetVSyncEventUnchecked(); 78 Kernel::KReadableEvent* GetVSyncEvent();
87 79
88 /// Signals the internal vsync event. 80 /// Signals the internal vsync event.
89 void SignalVSyncEvent(); 81 void SignalVSyncEvent();
@@ -104,7 +96,6 @@ public:
104 /// Resets the display for a new connection. 96 /// Resets the display for a new connection.
105 void Reset() { 97 void Reset() {
106 layers.clear(); 98 layers.clear();
107 got_vsync_event = false;
108 } 99 }
109 100
110 /// Attempts to find a layer with the given ID. 101 /// Attempts to find a layer with the given ID.
@@ -133,7 +124,6 @@ private:
133 124
134 std::vector<std::unique_ptr<Layer>> layers; 125 std::vector<std::unique_ptr<Layer>> layers;
135 Kernel::KEvent* vsync_event{}; 126 Kernel::KEvent* vsync_event{};
136 bool got_vsync_event{false};
137}; 127};
138 128
139} // namespace Service::VI 129} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 9ab8788e3..39d5be90d 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -343,8 +343,8 @@ private:
343 343
344class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { 344class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
345public: 345public:
346 explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_) 346 explicit IManagerDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
347 : ServiceFramework{system_, "IManagerDisplayService"}, nv_flinger{nv_flinger_} { 347 : ServiceFramework{system_, "IManagerDisplayService"}, nvnflinger{nvnflinger_} {
348 // clang-format off 348 // clang-format off
349 static const FunctionInfo functions[] = { 349 static const FunctionInfo functions[] = {
350 {200, nullptr, "AllocateProcessHeapBlock"}, 350 {200, nullptr, "AllocateProcessHeapBlock"},
@@ -440,7 +440,7 @@ private:
440 IPC::RequestParser rp{ctx}; 440 IPC::RequestParser rp{ctx};
441 const u64 display = rp.Pop<u64>(); 441 const u64 display = rp.Pop<u64>();
442 442
443 const Result rc = nv_flinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown; 443 const Result rc = nvnflinger.CloseDisplay(display) ? ResultSuccess : ResultUnknown;
444 444
445 IPC::ResponseBuilder rb{ctx, 2}; 445 IPC::ResponseBuilder rb{ctx, 2};
446 rb.Push(rc); 446 rb.Push(rc);
@@ -457,7 +457,7 @@ private:
457 "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}", 457 "(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
458 unknown, display, aruid); 458 unknown, display, aruid);
459 459
460 const auto layer_id = nv_flinger.CreateLayer(display); 460 const auto layer_id = nvnflinger.CreateLayer(display);
461 if (!layer_id) { 461 if (!layer_id) {
462 LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display); 462 LOG_ERROR(Service_VI, "Layer not found! display=0x{:016X}", display);
463 IPC::ResponseBuilder rb{ctx, 2}; 463 IPC::ResponseBuilder rb{ctx, 2};
@@ -494,14 +494,14 @@ private:
494 rb.Push(ResultSuccess); 494 rb.Push(ResultSuccess);
495 } 495 }
496 496
497 Nvnflinger::Nvnflinger& nv_flinger; 497 Nvnflinger::Nvnflinger& nvnflinger;
498}; 498};
499 499
500class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> { 500class IApplicationDisplayService final : public ServiceFramework<IApplicationDisplayService> {
501public: 501public:
502 IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nv_flinger_, 502 IApplicationDisplayService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_,
503 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_) 503 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server_)
504 : ServiceFramework{system_, "IApplicationDisplayService"}, nv_flinger{nv_flinger_}, 504 : ServiceFramework{system_, "IApplicationDisplayService"}, nvnflinger{nvnflinger_},
505 hos_binder_driver_server{hos_binder_driver_server_} { 505 hos_binder_driver_server{hos_binder_driver_server_} {
506 506
507 static const FunctionInfo functions[] = { 507 static const FunctionInfo functions[] = {
@@ -564,7 +564,7 @@ private:
564 564
565 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 565 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
566 rb.Push(ResultSuccess); 566 rb.Push(ResultSuccess);
567 rb.PushIpcInterface<ISystemDisplayService>(system, nv_flinger); 567 rb.PushIpcInterface<ISystemDisplayService>(system, nvnflinger);
568 } 568 }
569 569
570 void GetManagerDisplayService(HLERequestContext& ctx) { 570 void GetManagerDisplayService(HLERequestContext& ctx) {
@@ -572,7 +572,7 @@ private:
572 572
573 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 573 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
574 rb.Push(ResultSuccess); 574 rb.Push(ResultSuccess);
575 rb.PushIpcInterface<IManagerDisplayService>(system, nv_flinger); 575 rb.PushIpcInterface<IManagerDisplayService>(system, nvnflinger);
576 } 576 }
577 577
578 void GetIndirectDisplayTransactionService(HLERequestContext& ctx) { 578 void GetIndirectDisplayTransactionService(HLERequestContext& ctx) {
@@ -607,7 +607,7 @@ private:
607 607
608 ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet"); 608 ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
609 609
610 const auto display_id = nv_flinger.OpenDisplay(name); 610 const auto display_id = nvnflinger.OpenDisplay(name);
611 if (!display_id) { 611 if (!display_id) {
612 LOG_ERROR(Service_VI, "Display not found! display_name={}", name); 612 LOG_ERROR(Service_VI, "Display not found! display_name={}", name);
613 IPC::ResponseBuilder rb{ctx, 2}; 613 IPC::ResponseBuilder rb{ctx, 2};
@@ -624,7 +624,7 @@ private:
624 IPC::RequestParser rp{ctx}; 624 IPC::RequestParser rp{ctx};
625 const u64 display_id = rp.Pop<u64>(); 625 const u64 display_id = rp.Pop<u64>();
626 626
627 const Result rc = nv_flinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown; 627 const Result rc = nvnflinger.CloseDisplay(display_id) ? ResultSuccess : ResultUnknown;
628 628
629 IPC::ResponseBuilder rb{ctx, 2}; 629 IPC::ResponseBuilder rb{ctx, 2};
630 rb.Push(rc); 630 rb.Push(rc);
@@ -703,7 +703,7 @@ private:
703 703
704 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid); 704 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
705 705
706 const auto display_id = nv_flinger.OpenDisplay(display_name); 706 const auto display_id = nvnflinger.OpenDisplay(display_name);
707 if (!display_id) { 707 if (!display_id) {
708 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id); 708 LOG_ERROR(Service_VI, "Layer not found! layer_id={}", layer_id);
709 IPC::ResponseBuilder rb{ctx, 2}; 709 IPC::ResponseBuilder rb{ctx, 2};
@@ -711,7 +711,7 @@ private:
711 return; 711 return;
712 } 712 }
713 713
714 const auto buffer_queue_id = nv_flinger.FindBufferQueueId(*display_id, layer_id); 714 const auto buffer_queue_id = nvnflinger.FindBufferQueueId(*display_id, layer_id);
715 if (!buffer_queue_id) { 715 if (!buffer_queue_id) {
716 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id); 716 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", *display_id);
717 IPC::ResponseBuilder rb{ctx, 2}; 717 IPC::ResponseBuilder rb{ctx, 2};
@@ -719,7 +719,7 @@ private:
719 return; 719 return;
720 } 720 }
721 721
722 nv_flinger.OpenLayer(layer_id); 722 nvnflinger.OpenLayer(layer_id);
723 723
724 android::OutputParcel parcel; 724 android::OutputParcel parcel;
725 parcel.WriteInterface(NativeWindow{*buffer_queue_id}); 725 parcel.WriteInterface(NativeWindow{*buffer_queue_id});
@@ -737,7 +737,7 @@ private:
737 737
738 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id); 738 LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id);
739 739
740 nv_flinger.CloseLayer(layer_id); 740 nvnflinger.CloseLayer(layer_id);
741 741
742 IPC::ResponseBuilder rb{ctx, 2}; 742 IPC::ResponseBuilder rb{ctx, 2};
743 rb.Push(ResultSuccess); 743 rb.Push(ResultSuccess);
@@ -753,7 +753,7 @@ private:
753 753
754 // TODO(Subv): What's the difference between a Stray and a Managed layer? 754 // TODO(Subv): What's the difference between a Stray and a Managed layer?
755 755
756 const auto layer_id = nv_flinger.CreateLayer(display_id); 756 const auto layer_id = nvnflinger.CreateLayer(display_id);
757 if (!layer_id) { 757 if (!layer_id) {
758 LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id); 758 LOG_ERROR(Service_VI, "Layer not found! display_id={}", display_id);
759 IPC::ResponseBuilder rb{ctx, 2}; 759 IPC::ResponseBuilder rb{ctx, 2};
@@ -761,7 +761,7 @@ private:
761 return; 761 return;
762 } 762 }
763 763
764 const auto buffer_queue_id = nv_flinger.FindBufferQueueId(display_id, *layer_id); 764 const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id);
765 if (!buffer_queue_id) { 765 if (!buffer_queue_id) {
766 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); 766 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
767 IPC::ResponseBuilder rb{ctx, 2}; 767 IPC::ResponseBuilder rb{ctx, 2};
@@ -785,7 +785,7 @@ private:
785 const u64 layer_id = rp.Pop<u64>(); 785 const u64 layer_id = rp.Pop<u64>();
786 786
787 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); 787 LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id);
788 nv_flinger.DestroyLayer(layer_id); 788 nvnflinger.DestroyLayer(layer_id);
789 789
790 IPC::ResponseBuilder rb{ctx, 2}; 790 IPC::ResponseBuilder rb{ctx, 2};
791 rb.Push(ResultSuccess); 791 rb.Push(ResultSuccess);
@@ -798,7 +798,7 @@ private:
798 LOG_DEBUG(Service_VI, "called. display_id={}", display_id); 798 LOG_DEBUG(Service_VI, "called. display_id={}", display_id);
799 799
800 Kernel::KReadableEvent* vsync_event{}; 800 Kernel::KReadableEvent* vsync_event{};
801 const auto result = nv_flinger.FindVsyncEvent(&vsync_event, display_id); 801 const auto result = nvnflinger.FindVsyncEvent(&vsync_event, display_id);
802 if (result != ResultSuccess) { 802 if (result != ResultSuccess) {
803 if (result == ResultNotFound) { 803 if (result == ResultNotFound) {
804 LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id); 804 LOG_ERROR(Service_VI, "Vsync event was not found for display_id={}", display_id);
@@ -808,6 +808,12 @@ private:
808 rb.Push(result); 808 rb.Push(result);
809 return; 809 return;
810 } 810 }
811 if (vsync_event_fetched) {
812 IPC::ResponseBuilder rb{ctx, 2};
813 rb.Push(VI::ResultPermissionDenied);
814 return;
815 }
816 vsync_event_fetched = true;
811 817
812 IPC::ResponseBuilder rb{ctx, 2, 1}; 818 IPC::ResponseBuilder rb{ctx, 2, 1};
813 rb.Push(ResultSuccess); 819 rb.Push(ResultSuccess);
@@ -899,8 +905,9 @@ private:
899 } 905 }
900 } 906 }
901 907
902 Nvnflinger::Nvnflinger& nv_flinger; 908 Nvnflinger::Nvnflinger& nvnflinger;
903 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; 909 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
910 bool vsync_event_fetched{false};
904}; 911};
905 912
906static bool IsValidServiceAccess(Permission permission, Policy policy) { 913static bool IsValidServiceAccess(Permission permission, Policy policy) {
@@ -916,7 +923,7 @@ static bool IsValidServiceAccess(Permission permission, Policy policy) {
916} 923}
917 924
918void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system, 925void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
919 Nvnflinger::Nvnflinger& nv_flinger, 926 Nvnflinger::Nvnflinger& nvnflinger,
920 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server, 927 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server,
921 Permission permission) { 928 Permission permission) {
922 IPC::RequestParser rp{ctx}; 929 IPC::RequestParser rp{ctx};
@@ -931,19 +938,19 @@ void detail::GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
931 938
932 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 939 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
933 rb.Push(ResultSuccess); 940 rb.Push(ResultSuccess);
934 rb.PushIpcInterface<IApplicationDisplayService>(system, nv_flinger, hos_binder_driver_server); 941 rb.PushIpcInterface<IApplicationDisplayService>(system, nvnflinger, hos_binder_driver_server);
935} 942}
936 943
937void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger, 944void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
938 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) { 945 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server) {
939 auto server_manager = std::make_unique<ServerManager>(system); 946 auto server_manager = std::make_unique<ServerManager>(system);
940 947
941 server_manager->RegisterNamedService( 948 server_manager->RegisterNamedService(
942 "vi:m", std::make_shared<VI_M>(system, nv_flinger, hos_binder_driver_server)); 949 "vi:m", std::make_shared<VI_M>(system, nvnflinger, hos_binder_driver_server));
943 server_manager->RegisterNamedService( 950 server_manager->RegisterNamedService(
944 "vi:s", std::make_shared<VI_S>(system, nv_flinger, hos_binder_driver_server)); 951 "vi:s", std::make_shared<VI_S>(system, nvnflinger, hos_binder_driver_server));
945 server_manager->RegisterNamedService( 952 server_manager->RegisterNamedService(
946 "vi:u", std::make_shared<VI_U>(system, nv_flinger, hos_binder_driver_server)); 953 "vi:u", std::make_shared<VI_U>(system, nvnflinger, hos_binder_driver_server));
947 ServerManager::RunServer(std::move(server_manager)); 954 ServerManager::RunServer(std::move(server_manager));
948} 955}
949 956
diff --git a/src/core/hle/service/vi/vi.h b/src/core/hle/service/vi/vi.h
index a35b62f97..ee4bcbcfa 100644
--- a/src/core/hle/service/vi/vi.h
+++ b/src/core/hle/service/vi/vi.h
@@ -48,7 +48,7 @@ void GetDisplayServiceImpl(HLERequestContext& ctx, Core::System& system,
48 Permission permission); 48 Permission permission);
49} // namespace detail 49} // namespace detail
50 50
51void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nv_flinger, 51void LoopProcess(Core::System& system, Nvnflinger::Nvnflinger& nvnflinger,
52 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server); 52 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server);
53 53
54} // namespace Service::VI 54} // namespace Service::VI
diff --git a/src/hid_core/CMakeLists.txt b/src/hid_core/CMakeLists.txt
index cce4e6857..aa85502b5 100644
--- a/src/hid_core/CMakeLists.txt
+++ b/src/hid_core/CMakeLists.txt
@@ -36,6 +36,30 @@ add_library(hid_core STATIC
36 irsensor/processor_base.h 36 irsensor/processor_base.h
37 irsensor/tera_plugin_processor.cpp 37 irsensor/tera_plugin_processor.cpp
38 irsensor/tera_plugin_processor.h 38 irsensor/tera_plugin_processor.h
39 resources/abstracted_pad/abstract_battery_handler.cpp
40 resources/abstracted_pad/abstract_battery_handler.h
41 resources/abstracted_pad/abstract_button_handler.cpp
42 resources/abstracted_pad/abstract_button_handler.h
43 resources/abstracted_pad/abstract_ir_sensor_handler.cpp
44 resources/abstracted_pad/abstract_ir_sensor_handler.h
45 resources/abstracted_pad/abstract_led_handler.cpp
46 resources/abstracted_pad/abstract_led_handler.h
47 resources/abstracted_pad/abstract_mcu_handler.cpp
48 resources/abstracted_pad/abstract_mcu_handler.h
49 resources/abstracted_pad/abstract_nfc_handler.cpp
50 resources/abstracted_pad/abstract_nfc_handler.h
51 resources/abstracted_pad/abstract_pad.cpp
52 resources/abstracted_pad/abstract_pad.h
53 resources/abstracted_pad/abstract_pad_holder.cpp
54 resources/abstracted_pad/abstract_pad_holder.h
55 resources/abstracted_pad/abstract_palma_handler.cpp
56 resources/abstracted_pad/abstract_palma_handler.h
57 resources/abstracted_pad/abstract_properties_handler.cpp
58 resources/abstracted_pad/abstract_properties_handler.h
59 resources/abstracted_pad/abstract_sixaxis_handler.cpp
60 resources/abstracted_pad/abstract_sixaxis_handler.h
61 resources/abstracted_pad/abstract_vibration_handler.cpp
62 resources/abstracted_pad/abstract_vibration_handler.h
39 resources/debug_pad/debug_pad.cpp 63 resources/debug_pad/debug_pad.cpp
40 resources/debug_pad/debug_pad.h 64 resources/debug_pad/debug_pad.h
41 resources/debug_pad/debug_pad_types.h 65 resources/debug_pad/debug_pad_types.h
@@ -56,6 +80,8 @@ add_library(hid_core STATIC
56 resources/npad/npad_resource.cpp 80 resources/npad/npad_resource.cpp
57 resources/npad/npad_resource.h 81 resources/npad/npad_resource.h
58 resources/npad/npad_types.h 82 resources/npad/npad_types.h
83 resources/npad/npad_vibration.cpp
84 resources/npad/npad_vibration.h
59 resources/palma/palma.cpp 85 resources/palma/palma.cpp
60 resources/palma/palma.h 86 resources/palma/palma.h
61 resources/six_axis/console_six_axis.cpp 87 resources/six_axis/console_six_axis.cpp
@@ -78,6 +104,14 @@ add_library(hid_core STATIC
78 resources/touch_screen/touch_types.h 104 resources/touch_screen/touch_types.h
79 resources/unique_pad/unique_pad.cpp 105 resources/unique_pad/unique_pad.cpp
80 resources/unique_pad/unique_pad.h 106 resources/unique_pad/unique_pad.h
107 resources/vibration/gc_vibration_device.h
108 resources/vibration/gc_vibration_device.cpp
109 resources/vibration/n64_vibration_device.h
110 resources/vibration/n64_vibration_device.cpp
111 resources/vibration/vibration_base.h
112 resources/vibration/vibration_base.cpp
113 resources/vibration/vibration_device.h
114 resources/vibration/vibration_device.cpp
81 resources/applet_resource.cpp 115 resources/applet_resource.cpp
82 resources/applet_resource.h 116 resources/applet_resource.h
83 resources/controller_base.cpp 117 resources/controller_base.cpp
diff --git a/src/hid_core/frontend/emulated_controller.cpp b/src/hid_core/frontend/emulated_controller.cpp
index 3d2d1e9f9..a6a96935d 100644
--- a/src/hid_core/frontend/emulated_controller.cpp
+++ b/src/hid_core/frontend/emulated_controller.cpp
@@ -27,7 +27,7 @@ EmulatedController::~EmulatedController() = default;
27NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) { 27NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerType type) {
28 switch (type) { 28 switch (type) {
29 case Settings::ControllerType::ProController: 29 case Settings::ControllerType::ProController:
30 return NpadStyleIndex::ProController; 30 return NpadStyleIndex::Fullkey;
31 case Settings::ControllerType::DualJoyconDetached: 31 case Settings::ControllerType::DualJoyconDetached:
32 return NpadStyleIndex::JoyconDual; 32 return NpadStyleIndex::JoyconDual;
33 case Settings::ControllerType::LeftJoycon: 33 case Settings::ControllerType::LeftJoycon:
@@ -49,13 +49,13 @@ NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerTyp
49 case Settings::ControllerType::SegaGenesis: 49 case Settings::ControllerType::SegaGenesis:
50 return NpadStyleIndex::SegaGenesis; 50 return NpadStyleIndex::SegaGenesis;
51 default: 51 default:
52 return NpadStyleIndex::ProController; 52 return NpadStyleIndex::Fullkey;
53 } 53 }
54} 54}
55 55
56Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) { 56Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleIndex type) {
57 switch (type) { 57 switch (type) {
58 case NpadStyleIndex::ProController: 58 case NpadStyleIndex::Fullkey:
59 return Settings::ControllerType::ProController; 59 return Settings::ControllerType::ProController;
60 case NpadStyleIndex::JoyconDual: 60 case NpadStyleIndex::JoyconDual:
61 return Settings::ControllerType::DualJoyconDetached; 61 return Settings::ControllerType::DualJoyconDetached;
@@ -106,7 +106,7 @@ void EmulatedController::ReloadFromSettings() {
106 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); 106 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
107 original_npad_type = npad_type; 107 original_npad_type = npad_type;
108 } else { 108 } else {
109 SetNpadStyleIndex(NpadStyleIndex::ProController); 109 SetNpadStyleIndex(NpadStyleIndex::Fullkey);
110 original_npad_type = npad_type; 110 original_npad_type = npad_type;
111 } 111 }
112 112
@@ -1073,7 +1073,7 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
1073 .body = GetNpadColor(controller.color_values[index].body), 1073 .body = GetNpadColor(controller.color_values[index].body),
1074 .button = GetNpadColor(controller.color_values[index].buttons), 1074 .button = GetNpadColor(controller.color_values[index].buttons),
1075 }; 1075 };
1076 if (npad_type == NpadStyleIndex::ProController) { 1076 if (npad_type == NpadStyleIndex::Fullkey) {
1077 controller.colors_state.left = { 1077 controller.colors_state.left = {
1078 .body = GetNpadColor(controller.color_values[index].left_grip), 1078 .body = GetNpadColor(controller.color_values[index].left_grip),
1079 .button = GetNpadColor(controller.color_values[index].buttons), 1079 .button = GetNpadColor(controller.color_values[index].buttons),
@@ -1356,7 +1356,7 @@ bool EmulatedController::HasNfc() const {
1356 switch (npad_type) { 1356 switch (npad_type) {
1357 case NpadStyleIndex::JoyconRight: 1357 case NpadStyleIndex::JoyconRight:
1358 case NpadStyleIndex::JoyconDual: 1358 case NpadStyleIndex::JoyconDual:
1359 case NpadStyleIndex::ProController: 1359 case NpadStyleIndex::Fullkey:
1360 case NpadStyleIndex::Handheld: 1360 case NpadStyleIndex::Handheld:
1361 break; 1361 break;
1362 default: 1362 default:
@@ -1548,7 +1548,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
1548 // Fallback Fullkey controllers to Pro controllers 1548 // Fallback Fullkey controllers to Pro controllers
1549 if (IsControllerFullkey() && supported_style_tag.fullkey) { 1549 if (IsControllerFullkey() && supported_style_tag.fullkey) {
1550 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); 1550 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
1551 SetNpadStyleIndex(NpadStyleIndex::ProController); 1551 SetNpadStyleIndex(NpadStyleIndex::Fullkey);
1552 Connect(); 1552 Connect();
1553 return; 1553 return;
1554 } 1554 }
@@ -1556,13 +1556,13 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
1556 // Fallback Dual joycon controllers to Pro controllers 1556 // Fallback Dual joycon controllers to Pro controllers
1557 if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) { 1557 if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) {
1558 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); 1558 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
1559 SetNpadStyleIndex(NpadStyleIndex::ProController); 1559 SetNpadStyleIndex(NpadStyleIndex::Fullkey);
1560 Connect(); 1560 Connect();
1561 return; 1561 return;
1562 } 1562 }
1563 1563
1564 // Fallback Pro controllers to Dual joycon 1564 // Fallback Pro controllers to Dual joycon
1565 if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) { 1565 if (npad_type == NpadStyleIndex::Fullkey && supported_style_tag.joycon_dual) {
1566 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type); 1566 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type);
1567 SetNpadStyleIndex(NpadStyleIndex::JoyconDual); 1567 SetNpadStyleIndex(NpadStyleIndex::JoyconDual);
1568 Connect(); 1568 Connect();
@@ -1577,7 +1577,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
1577 std::scoped_lock lock{mutex}; 1577 std::scoped_lock lock{mutex};
1578 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; 1578 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
1579 switch (type) { 1579 switch (type) {
1580 case NpadStyleIndex::ProController: 1580 case NpadStyleIndex::Fullkey:
1581 case NpadStyleIndex::GameCube: 1581 case NpadStyleIndex::GameCube:
1582 case NpadStyleIndex::NES: 1582 case NpadStyleIndex::NES:
1583 case NpadStyleIndex::SNES: 1583 case NpadStyleIndex::SNES:
@@ -1593,7 +1593,7 @@ bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
1593 std::scoped_lock lock{mutex}; 1593 std::scoped_lock lock{mutex};
1594 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; 1594 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
1595 switch (type) { 1595 switch (type) {
1596 case NpadStyleIndex::ProController: 1596 case NpadStyleIndex::Fullkey:
1597 return supported_style_tag.fullkey.As<bool>(); 1597 return supported_style_tag.fullkey.As<bool>();
1598 case NpadStyleIndex::Handheld: 1598 case NpadStyleIndex::Handheld:
1599 return supported_style_tag.handheld.As<bool>(); 1599 return supported_style_tag.handheld.As<bool>();
diff --git a/src/hid_core/hid_types.h b/src/hid_core/hid_types.h
index a81ed6af0..2c3f02f34 100644
--- a/src/hid_core/hid_types.h
+++ b/src/hid_core/hid_types.h
@@ -220,6 +220,7 @@ enum class NpadIdType : u32 {
220}; 220};
221 221
222enum class NpadInterfaceType : u8 { 222enum class NpadInterfaceType : u8 {
223 None = 0,
223 Bluetooth = 1, 224 Bluetooth = 1,
224 Rail = 2, 225 Rail = 2,
225 Usb = 3, 226 Usb = 3,
@@ -229,7 +230,7 @@ enum class NpadInterfaceType : u8 {
229// This is nn::hid::NpadStyleIndex 230// This is nn::hid::NpadStyleIndex
230enum class NpadStyleIndex : u8 { 231enum class NpadStyleIndex : u8 {
231 None = 0, 232 None = 0,
232 ProController = 3, 233 Fullkey = 3,
233 Handheld = 4, 234 Handheld = 4,
234 HandheldNES = 4, 235 HandheldNES = 4,
235 JoyconDual = 5, 236 JoyconDual = 5,
diff --git a/src/hid_core/hid_util.h b/src/hid_core/hid_util.h
index 94ff2d23a..397a87472 100644
--- a/src/hid_core/hid_util.h
+++ b/src/hid_core/hid_util.h
@@ -42,7 +42,7 @@ constexpr Result IsSixaxisHandleValid(const Core::HID::SixAxisSensorHandle& hand
42 42
43constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) { 43constexpr Result IsVibrationHandleValid(const Core::HID::VibrationDeviceHandle& handle) {
44 switch (handle.npad_type) { 44 switch (handle.npad_type) {
45 case Core::HID::NpadStyleIndex::ProController: 45 case Core::HID::NpadStyleIndex::Fullkey:
46 case Core::HID::NpadStyleIndex::Handheld: 46 case Core::HID::NpadStyleIndex::Handheld:
47 case Core::HID::NpadStyleIndex::JoyconDual: 47 case Core::HID::NpadStyleIndex::JoyconDual:
48 case Core::HID::NpadStyleIndex::JoyconLeft: 48 case Core::HID::NpadStyleIndex::JoyconLeft:
diff --git a/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp
new file mode 100644
index 000000000..62fbbb0a7
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.cpp
@@ -0,0 +1,197 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/core_timing.h"
5#include "hid_core/hid_result.h"
6#include "hid_core/hid_util.h"
7#include "hid_core/resources/abstracted_pad/abstract_battery_handler.h"
8#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
9#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
10#include "hid_core/resources/applet_resource.h"
11#include "hid_core/resources/npad/npad_types.h"
12#include "hid_core/resources/shared_memory_format.h"
13
14namespace Service::HID {
15
16NpadAbstractBatteryHandler::NpadAbstractBatteryHandler() {}
17
18NpadAbstractBatteryHandler::~NpadAbstractBatteryHandler() = default;
19
20void NpadAbstractBatteryHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
21 abstract_pad_holder = holder;
22}
23
24void NpadAbstractBatteryHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
25 applet_resource_holder = applet_resource;
26}
27
28void NpadAbstractBatteryHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
29 properties_handler = handler;
30}
31
32Result NpadAbstractBatteryHandler::IncrementRefCounter() {
33 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
34 return ResultNpadHandlerOverflow;
35 }
36 ref_counter++;
37 return ResultSuccess;
38}
39
40Result NpadAbstractBatteryHandler::DecrementRefCounter() {
41 if (ref_counter == 0) {
42 return ResultNpadHandlerNotInitialized;
43 }
44 ref_counter--;
45 return ResultSuccess;
46}
47
48Result NpadAbstractBatteryHandler::UpdateBatteryState(u64 aruid) {
49 const auto npad_index = NpadIdTypeToIndex(properties_handler->GetNpadId());
50 AruidData* aruid_data = applet_resource_holder->applet_resource->GetAruidData(aruid);
51 if (aruid_data == nullptr) {
52 return ResultSuccess;
53 }
54
55 auto& npad_internal_state =
56 aruid_data->shared_memory_format->npad.npad_entry[npad_index].internal_state;
57 auto& system_properties = npad_internal_state.system_properties;
58
59 system_properties.is_charging_joy_dual.Assign(dual_battery.is_charging);
60 system_properties.is_powered_joy_dual.Assign(dual_battery.is_powered);
61 system_properties.is_charging_joy_left.Assign(left_battery.is_charging);
62 system_properties.is_powered_joy_left.Assign(left_battery.is_powered);
63 system_properties.is_charging_joy_right.Assign(right_battery.is_charging);
64 system_properties.is_powered_joy_right.Assign(right_battery.is_powered);
65
66 npad_internal_state.battery_level_dual = dual_battery.battery_level;
67 npad_internal_state.battery_level_left = left_battery.battery_level;
68 npad_internal_state.battery_level_right = right_battery.battery_level;
69
70 return ResultSuccess;
71}
72
73void NpadAbstractBatteryHandler::UpdateBatteryState() {
74 if (ref_counter == 0) {
75 return;
76 }
77 has_new_battery_data = GetNewBatteryState();
78}
79
80bool NpadAbstractBatteryHandler::GetNewBatteryState() {
81 bool has_changed = false;
82 Core::HID::NpadPowerInfo new_dual_battery_state{};
83 Core::HID::NpadPowerInfo new_left_battery_state{};
84 Core::HID::NpadPowerInfo new_right_battery_state{};
85 std::array<IAbstractedPad*, 5> abstract_pads{};
86 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
87
88 for (std::size_t i = 0; i < count; i++) {
89 auto* abstract_pad = abstract_pads[i];
90 if (!abstract_pad->internal_flags.is_connected) {
91 continue;
92 }
93 const auto power_info = abstract_pad->power_info;
94 if (power_info.battery_level > Core::HID::NpadBatteryLevel::Full) {
95 // Abort
96 continue;
97 }
98
99 const auto style = abstract_pad->assignment_style;
100
101 if (style.is_external_assigned || style.is_handheld_assigned) {
102 new_dual_battery_state = power_info;
103 }
104 if (style.is_external_left_assigned || style.is_handheld_left_assigned) {
105 new_left_battery_state = power_info;
106 }
107 if (style.is_external_right_assigned || style.is_handheld_right_assigned) {
108 new_right_battery_state = power_info;
109 }
110
111 if (abstract_pad->internal_flags.is_battery_low_ovln_required) {
112 if (abstract_pad->interface_type == Core::HID::NpadInterfaceType::Rail) {
113 // TODO
114 }
115 abstract_pad->internal_flags.is_battery_low_ovln_required.Assign(false);
116 }
117 }
118
119 if (dual_battery.battery_level != new_dual_battery_state.battery_level ||
120 dual_battery.is_charging != new_dual_battery_state.is_charging ||
121 dual_battery.is_powered != new_dual_battery_state.is_powered) {
122 has_changed = true;
123 dual_battery = new_dual_battery_state;
124 }
125
126 if (left_battery.battery_level != new_left_battery_state.battery_level ||
127 left_battery.is_charging != new_left_battery_state.is_charging ||
128 left_battery.is_powered != new_left_battery_state.is_powered) {
129 has_changed = true;
130 left_battery = new_left_battery_state;
131 }
132
133 if (right_battery.battery_level != new_right_battery_state.battery_level ||
134 right_battery.is_charging != new_right_battery_state.is_charging ||
135 right_battery.is_powered != new_right_battery_state.is_powered) {
136 has_changed = true;
137 right_battery = new_right_battery_state;
138 }
139
140 return has_changed;
141}
142
143void NpadAbstractBatteryHandler::UpdateCoreBatteryState() {
144 if (ref_counter == 0) {
145 return;
146 }
147 if (!has_new_battery_data) {
148 return;
149 }
150
151 UpdateBatteryState(0);
152}
153
154void NpadAbstractBatteryHandler::InitializeBatteryState(u64 aruid) {
155 UpdateBatteryState(aruid);
156}
157
158bool NpadAbstractBatteryHandler::HasBattery() const {
159 std::array<IAbstractedPad*, 5> abstract_pads{};
160 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
161
162 for (std::size_t i = 0; i < count; i++) {
163 const auto* abstract_pad = abstract_pads[i];
164 if (!abstract_pad->internal_flags.is_connected) {
165 continue;
166 }
167 return abstract_pad->disabled_feature_set.has_fullkey_battery ||
168 abstract_pad->disabled_feature_set.has_left_right_joy_battery;
169 }
170
171 return false;
172}
173
174void NpadAbstractBatteryHandler::HasLeftRightBattery(bool& has_left, bool& has_right) const {
175 std::array<IAbstractedPad*, 5> abstract_pads{};
176 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
177
178 has_left = false;
179 has_right = false;
180
181 for (std::size_t i = 0; i < count; i++) {
182 const auto* abstract_pad = abstract_pads[i];
183 if (!abstract_pad->internal_flags.is_connected) {
184 continue;
185 }
186 if (!abstract_pad->disabled_feature_set.has_fullkey_battery &&
187 !abstract_pad->disabled_feature_set.has_left_right_joy_battery) {
188 continue;
189 }
190 has_left = abstract_pad->assignment_style.is_external_left_assigned ||
191 abstract_pad->assignment_style.is_handheld_left_assigned;
192 has_right = abstract_pad->assignment_style.is_external_right_assigned ||
193 abstract_pad->assignment_style.is_handheld_right_assigned;
194 }
195}
196
197} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h
new file mode 100644
index 000000000..85ac5eb72
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_battery_handler.h
@@ -0,0 +1,49 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8#include "hid_core/hid_types.h"
9
10namespace Service::HID {
11struct AppletResourceHolder;
12class NpadAbstractedPadHolder;
13class NpadAbstractPropertiesHandler;
14
15/// Handles Npad request from HID interfaces
16class NpadAbstractBatteryHandler final {
17public:
18 explicit NpadAbstractBatteryHandler();
19 ~NpadAbstractBatteryHandler();
20
21 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
22 void SetAppletResource(AppletResourceHolder* applet_resource);
23 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
24
25 Result IncrementRefCounter();
26 Result DecrementRefCounter();
27
28 Result UpdateBatteryState(u64 aruid);
29 void UpdateBatteryState();
30 bool GetNewBatteryState();
31 void UpdateCoreBatteryState();
32 void InitializeBatteryState(u64 aruid);
33
34 bool HasBattery() const;
35 void HasLeftRightBattery(bool& has_left, bool& has_right) const;
36
37private:
38 AppletResourceHolder* applet_resource_holder{nullptr};
39 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
40 NpadAbstractPropertiesHandler* properties_handler{nullptr};
41
42 s32 ref_counter{};
43 Core::HID::NpadPowerInfo dual_battery{};
44 Core::HID::NpadPowerInfo left_battery{};
45 Core::HID::NpadPowerInfo right_battery{};
46 bool has_new_battery_data{};
47};
48
49} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp
new file mode 100644
index 000000000..587169433
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_button_handler.cpp
@@ -0,0 +1,199 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/hid_util.h"
6#include "hid_core/resources/abstracted_pad/abstract_button_handler.h"
7#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
8#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
9#include "hid_core/resources/applet_resource.h"
10#include "hid_core/resources/npad/npad_resource.h"
11#include "hid_core/resources/npad/npad_types.h"
12#include "hid_core/resources/shared_memory_format.h"
13
14namespace Service::HID {
15
16NpadAbstractButtonHandler::NpadAbstractButtonHandler() {}
17
18NpadAbstractButtonHandler::~NpadAbstractButtonHandler() = default;
19
20void NpadAbstractButtonHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
21 abstract_pad_holder = holder;
22}
23
24void NpadAbstractButtonHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
25 applet_resource_holder = applet_resource;
26}
27
28void NpadAbstractButtonHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
29 properties_handler = handler;
30}
31
32Result NpadAbstractButtonHandler::IncrementRefCounter() {
33 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
34 return ResultNpadHandlerOverflow;
35 }
36 ref_counter++;
37 return ResultSuccess;
38}
39
40Result NpadAbstractButtonHandler::DecrementRefCounter() {
41 if (ref_counter == 0) {
42 return ResultNpadHandlerNotInitialized;
43 }
44 ref_counter--;
45 return ResultSuccess;
46}
47
48Result NpadAbstractButtonHandler::UpdateAllButtonWithHomeProtection(u64 aruid) {
49 const Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
50 auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);
51
52 if (data == nullptr) {
53 return ResultSuccess;
54 }
55
56 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
57 UpdateButtonLifo(npad_entry, aruid);
58
59 bool is_home_button_protection_enabled{};
60 const auto result = applet_resource_holder->shared_npad_resource->GetHomeProtectionEnabled(
61 is_home_button_protection_enabled, aruid, npad_id);
62
63 if (result.IsError()) {
64 return ResultSuccess;
65 }
66
67 npad_entry.internal_state.button_properties.is_home_button_protection_enabled.Assign(
68 is_home_button_protection_enabled);
69
70 return ResultSuccess;
71}
72
73void NpadAbstractButtonHandler::UpdateAllButtonLifo() {
74 Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
75 for (std::size_t i = 0; i < AruidIndexMax; i++) {
76 auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
77 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
78 UpdateButtonLifo(npad_entry, data->aruid);
79 }
80}
81
82void NpadAbstractButtonHandler::UpdateCoreBatteryState() {
83 Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
84 for (std::size_t i = 0; i < AruidIndexMax; i++) {
85 auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
86 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
87 UpdateButtonLifo(npad_entry, data->aruid);
88 }
89}
90
91void NpadAbstractButtonHandler::UpdateButtonState(u64 aruid) {
92 Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
93 auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);
94 if (data == nullptr) {
95 return;
96 }
97 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
98 UpdateButtonLifo(npad_entry, aruid);
99}
100
101Result NpadAbstractButtonHandler::SetHomeProtection(bool is_enabled, u64 aruid) {
102 const Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
103 auto result = applet_resource_holder->shared_npad_resource->SetHomeProtectionEnabled(
104 aruid, npad_id, is_enabled);
105 if (result.IsError()) {
106 return result;
107 }
108
109 auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);
110 if (data == nullptr) {
111 return ResultSuccess;
112 }
113
114 bool is_home_protection_enabled{};
115 result = applet_resource_holder->shared_npad_resource->GetHomeProtectionEnabled(
116 is_home_protection_enabled, aruid, npad_id);
117 if (result.IsError()) {
118 return ResultSuccess;
119 }
120
121 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
122 npad_entry.internal_state.button_properties.is_home_button_protection_enabled.Assign(
123 is_home_protection_enabled);
124 return ResultSuccess;
125}
126
127bool NpadAbstractButtonHandler::IsButtonPressedOnConsoleMode() {
128 return is_button_pressed_on_console_mode;
129}
130
131void NpadAbstractButtonHandler::EnableCenterClamp() {
132 std::array<IAbstractedPad*, 5> abstract_pads{};
133 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
134
135 for (std::size_t i = 0; i < count; i++) {
136 auto* abstract_pad = abstract_pads[i];
137 if (!abstract_pad->internal_flags.is_connected) {
138 continue;
139 }
140 abstract_pad->internal_flags.use_center_clamp.Assign(true);
141 }
142}
143
144void NpadAbstractButtonHandler::UpdateButtonLifo(NpadSharedMemoryEntry& shared_memory, u64 aruid) {
145 auto* npad_resource = applet_resource_holder->shared_npad_resource;
146 Core::HID::NpadStyleTag style_tag = {properties_handler->GetStyleSet(aruid)};
147 style_tag.system_ext.Assign(npad_resource->GetActiveData()->GetNpadSystemExtState());
148
149 UpdateNpadFullkeyLifo(style_tag, 0, aruid, shared_memory);
150 UpdateHandheldLifo(style_tag, 1, aruid, shared_memory);
151 UpdateJoyconDualLifo(style_tag, 2, aruid, shared_memory);
152 UpdateJoyconLeftLifo(style_tag, 3, aruid, shared_memory);
153 UpdateJoyconRightLifo(style_tag, 4, aruid, shared_memory);
154 UpdatePalmaLifo(style_tag, 5, aruid, shared_memory);
155 UpdateSystemExtLifo(style_tag, 6, aruid, shared_memory);
156}
157
158void NpadAbstractButtonHandler::UpdateNpadFullkeyLifo(Core::HID::NpadStyleTag style_tag,
159 int style_index, u64 aruid,
160 NpadSharedMemoryEntry& shared_memory) {
161 // TODO
162}
163
164void NpadAbstractButtonHandler::UpdateHandheldLifo(Core::HID::NpadStyleTag style_tag,
165 int style_index, u64 aruid,
166 NpadSharedMemoryEntry& shared_memory) {
167 // TODO
168}
169
170void NpadAbstractButtonHandler::UpdateJoyconDualLifo(Core::HID::NpadStyleTag style_tag,
171 int style_index, u64 aruid,
172 NpadSharedMemoryEntry& shared_memory) {
173 // TODO
174}
175
176void NpadAbstractButtonHandler::UpdateJoyconLeftLifo(Core::HID::NpadStyleTag style_tag,
177 int style_index, u64 aruid,
178 NpadSharedMemoryEntry& shared_memory) {
179 // TODO
180}
181
182void NpadAbstractButtonHandler::UpdateJoyconRightLifo(Core::HID::NpadStyleTag style_tag,
183 int style_index, u64 aruid,
184 NpadSharedMemoryEntry& shared_memory) {
185 // TODO
186}
187
188void NpadAbstractButtonHandler::UpdateSystemExtLifo(Core::HID::NpadStyleTag style_tag,
189 int style_index, u64 aruid,
190 NpadSharedMemoryEntry& shared_memory) {
191 // TODO
192}
193
194void NpadAbstractButtonHandler::UpdatePalmaLifo(Core::HID::NpadStyleTag style_tag, int style_index,
195 u64 aruid, NpadSharedMemoryEntry& shared_memory) {
196 // TODO
197}
198
199} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_button_handler.h b/src/hid_core/resources/abstracted_pad/abstract_button_handler.h
new file mode 100644
index 000000000..01eafe96d
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_button_handler.h
@@ -0,0 +1,75 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8#include "hid_core/hid_types.h"
9
10namespace Service::HID {
11struct NpadSharedMemoryEntry;
12
13struct AppletResourceHolder;
14class NpadAbstractedPadHolder;
15class NpadAbstractPropertiesHandler;
16
17/// Handles Npad request from HID interfaces
18class NpadAbstractButtonHandler final {
19public:
20 explicit NpadAbstractButtonHandler();
21 ~NpadAbstractButtonHandler();
22
23 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
24 void SetAppletResource(AppletResourceHolder* applet_resource);
25 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
26
27 Result IncrementRefCounter();
28 Result DecrementRefCounter();
29
30 Result UpdateAllButtonWithHomeProtection(u64 aruid);
31
32 void UpdateAllButtonLifo();
33 void UpdateCoreBatteryState();
34 void UpdateButtonState(u64 aruid);
35
36 Result SetHomeProtection(bool is_enabled, u64 aruid);
37 bool IsButtonPressedOnConsoleMode();
38 void EnableCenterClamp();
39
40 void UpdateButtonLifo(NpadSharedMemoryEntry& shared_memory, u64 aruid);
41
42 void UpdateNpadFullkeyLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
43 NpadSharedMemoryEntry& shared_memory);
44 void UpdateHandheldLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
45 NpadSharedMemoryEntry& shared_memory);
46 void UpdateJoyconDualLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
47 NpadSharedMemoryEntry& shared_memory);
48 void UpdateJoyconLeftLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
49 NpadSharedMemoryEntry& shared_memory);
50 void UpdateJoyconRightLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
51 NpadSharedMemoryEntry& shared_memory);
52 void UpdateSystemExtLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
53 NpadSharedMemoryEntry& shared_memory);
54 void UpdatePalmaLifo(Core::HID::NpadStyleTag style_tag, int index, u64 aruid,
55 NpadSharedMemoryEntry& shared_memory);
56
57private:
58 struct GcTrigger {
59 float left;
60 float right;
61 };
62
63 AppletResourceHolder* applet_resource_holder{nullptr};
64 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
65 NpadAbstractPropertiesHandler* properties_handler{nullptr};
66
67 s32 ref_counter{};
68
69 bool is_button_pressed_on_console_mode{};
70
71 u64 gc_sampling_number{};
72 GcTrigger gc_trigger_state{};
73};
74
75} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp
new file mode 100644
index 000000000..d4e4181bf
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.cpp
@@ -0,0 +1,126 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/kernel/k_event.h"
5#include "core/hle/kernel/k_readable_event.h"
6#include "hid_core/hid_result.h"
7#include "hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h"
8#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
9#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
10#include "hid_core/resources/npad/npad_types.h"
11
12namespace Service::HID {
13
14NpadAbstractIrSensorHandler::NpadAbstractIrSensorHandler() {}
15
16NpadAbstractIrSensorHandler::~NpadAbstractIrSensorHandler() = default;
17
18void NpadAbstractIrSensorHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
19 abstract_pad_holder = holder;
20}
21
22void NpadAbstractIrSensorHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
23 properties_handler = handler;
24}
25
26Result NpadAbstractIrSensorHandler::IncrementRefCounter() {
27 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
28 return ResultNpadHandlerOverflow;
29 }
30 ref_counter++;
31 return ResultSuccess;
32}
33
34Result NpadAbstractIrSensorHandler::DecrementRefCounter() {
35 if (ref_counter == 0) {
36 return ResultNpadHandlerNotInitialized;
37 }
38 ref_counter--;
39 return ResultSuccess;
40}
41
42void NpadAbstractIrSensorHandler::UpdateIrSensorState() {
43 const auto previous_state = sensor_state;
44 std::array<IAbstractedPad*, 5> abstract_pads{};
45 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
46
47 if (count == 0) {
48 sensor_state = NpadIrSensorState::Disabled;
49 if (sensor_state == previous_state) {
50 return;
51 }
52 ir_sensor_event->Signal();
53 return;
54 }
55
56 bool is_found{};
57 for (std::size_t i = 0; i < count; i++) {
58 auto* abstract_pad = abstract_pads[i];
59 if (!abstract_pad->internal_flags.is_connected) {
60 continue;
61 }
62 if (!abstract_pad->disabled_feature_set.has_bluetooth_address) {
63 continue;
64 }
65 is_found = true;
66 xcd_handle = abstract_pad->xcd_handle;
67 }
68
69 if (is_found) {
70 if (sensor_state == NpadIrSensorState::Active) {
71 return;
72 }
73 sensor_state = NpadIrSensorState::Available;
74 if (sensor_state == previous_state) {
75 return;
76 }
77 ir_sensor_event->Signal();
78 return;
79 }
80
81 sensor_state = NpadIrSensorState::Unavailable;
82 if (sensor_state == previous_state) {
83 return;
84 }
85
86 ir_sensor_event->Signal();
87 return;
88}
89
90Result NpadAbstractIrSensorHandler::ActivateIrSensor(bool is_enabled) {
91 if (sensor_state == NpadIrSensorState::Unavailable) {
92 return ResultIrSensorIsNotReady;
93 }
94 if (is_enabled && sensor_state == NpadIrSensorState::Available) {
95 sensor_state = NpadIrSensorState::Active;
96 } else {
97 if (is_enabled) {
98 return ResultSuccess;
99 }
100 if (sensor_state != NpadIrSensorState::Active) {
101 return ResultSuccess;
102 }
103 sensor_state = NpadIrSensorState::Available;
104 }
105 ir_sensor_event->Signal();
106 return ResultSuccess;
107}
108
109Result NpadAbstractIrSensorHandler::GetIrSensorEventHandle(Kernel::KReadableEvent** out_event) {
110 *out_event = &ir_sensor_event->GetReadableEvent();
111 return ResultSuccess;
112}
113
114Result NpadAbstractIrSensorHandler::GetXcdHandleForNpadWithIrSensor(u64& handle) const {
115 if (sensor_state < NpadIrSensorState::Available) {
116 return ResultIrSensorIsNotReady;
117 }
118 handle = xcd_handle;
119 return ResultSuccess;
120}
121
122NpadIrSensorState NpadAbstractIrSensorHandler::GetSensorState() const {
123 return sensor_state;
124}
125
126} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h
new file mode 100644
index 000000000..fe8e005af
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h
@@ -0,0 +1,56 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8#include "hid_core/hid_types.h"
9
10namespace Kernel {
11class KEvent;
12class KReadableEvent;
13} // namespace Kernel
14
15enum class NpadIrSensorState : u32 {
16 Disabled,
17 Unavailable,
18 Available,
19 Active,
20};
21
22namespace Service::HID {
23class NpadAbstractedPadHolder;
24class NpadAbstractPropertiesHandler;
25
26/// Handles Npad request from HID interfaces
27class NpadAbstractIrSensorHandler final {
28public:
29 explicit NpadAbstractIrSensorHandler();
30 ~NpadAbstractIrSensorHandler();
31
32 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
33 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
34
35 Result IncrementRefCounter();
36 Result DecrementRefCounter();
37
38 void UpdateIrSensorState();
39 Result ActivateIrSensor(bool param_2);
40
41 Result GetIrSensorEventHandle(Kernel::KReadableEvent** out_event);
42
43 Result GetXcdHandleForNpadWithIrSensor(u64& handle) const;
44
45 NpadIrSensorState GetSensorState() const;
46
47private:
48 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
49 NpadAbstractPropertiesHandler* properties_handler{nullptr};
50
51 s32 ref_counter{};
52 Kernel::KEvent* ir_sensor_event{nullptr};
53 u64 xcd_handle{};
54 NpadIrSensorState sensor_state{};
55};
56} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp
new file mode 100644
index 000000000..0b2bfe88d
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_led_handler.cpp
@@ -0,0 +1,123 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/core_timing.h"
5#include "hid_core/hid_result.h"
6#include "hid_core/hid_util.h"
7#include "hid_core/resources/abstracted_pad/abstract_led_handler.h"
8#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
9#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
10#include "hid_core/resources/applet_resource.h"
11#include "hid_core/resources/npad/npad_types.h"
12
13namespace Service::HID {
14
15NpadAbstractLedHandler::NpadAbstractLedHandler() {}
16
17NpadAbstractLedHandler::~NpadAbstractLedHandler() = default;
18
19void NpadAbstractLedHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
20 abstract_pad_holder = holder;
21}
22
23void NpadAbstractLedHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
24 applet_resource_holder = applet_resource;
25}
26
27void NpadAbstractLedHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
28 properties_handler = handler;
29}
30
31Result NpadAbstractLedHandler::IncrementRefCounter() {
32 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
33 return ResultNpadHandlerOverflow;
34 }
35 ref_counter++;
36 return ResultSuccess;
37}
38
39Result NpadAbstractLedHandler::DecrementRefCounter() {
40 if (ref_counter == 0) {
41 return ResultNpadHandlerNotInitialized;
42 }
43 ref_counter--;
44 return ResultSuccess;
45}
46
47void NpadAbstractLedHandler::SetNpadLedHandlerLedPattern() {
48 const auto npad_id = properties_handler->GetNpadId();
49
50 switch (npad_id) {
51 case Core::HID::NpadIdType::Player1:
52 left_pattern = Core::HID::LedPattern{1, 0, 0, 0};
53 break;
54 case Core::HID::NpadIdType::Player2:
55 left_pattern = Core::HID::LedPattern{1, 1, 0, 0};
56 break;
57 case Core::HID::NpadIdType::Player3:
58 left_pattern = Core::HID::LedPattern{1, 1, 1, 0};
59 break;
60 case Core::HID::NpadIdType::Player4:
61 left_pattern = Core::HID::LedPattern{1, 1, 1, 1};
62 break;
63 case Core::HID::NpadIdType::Player5:
64 left_pattern = Core::HID::LedPattern{1, 0, 0, 1};
65 break;
66 case Core::HID::NpadIdType::Player6:
67 left_pattern = Core::HID::LedPattern{1, 0, 1, 0};
68 break;
69 case Core::HID::NpadIdType::Player7:
70 left_pattern = Core::HID::LedPattern{1, 0, 1, 1};
71 break;
72 case Core::HID::NpadIdType::Player8:
73 left_pattern = Core::HID::LedPattern{0, 1, 1, 0};
74 break;
75 case Core::HID::NpadIdType::Other:
76 case Core::HID::NpadIdType::Handheld:
77 left_pattern = Core::HID::LedPattern{0, 0, 0, 0};
78 break;
79 default:
80 ASSERT_MSG(false, "Invalid npad id type");
81 break;
82 }
83
84 switch (npad_id) {
85 case Core::HID::NpadIdType::Player1:
86 right_pattern = Core::HID::LedPattern{0, 0, 0, 1};
87 break;
88 case Core::HID::NpadIdType::Player2:
89 right_pattern = Core::HID::LedPattern{0, 1, 1, 1};
90 break;
91 case Core::HID::NpadIdType::Player3:
92 right_pattern = Core::HID::LedPattern{0, 1, 1, 1};
93 break;
94 case Core::HID::NpadIdType::Player4:
95 right_pattern = Core::HID::LedPattern{1, 1, 1, 1};
96 break;
97 case Core::HID::NpadIdType::Player5:
98 right_pattern = Core::HID::LedPattern{1, 0, 0, 1};
99 break;
100 case Core::HID::NpadIdType::Player6:
101 right_pattern = Core::HID::LedPattern{0, 1, 0, 1};
102 break;
103 case Core::HID::NpadIdType::Player7:
104 right_pattern = Core::HID::LedPattern{1, 1, 0, 1};
105 break;
106 case Core::HID::NpadIdType::Player8:
107 right_pattern = Core::HID::LedPattern{0, 1, 1, 0};
108 break;
109 case Core::HID::NpadIdType::Other:
110 case Core::HID::NpadIdType::Handheld:
111 right_pattern = Core::HID::LedPattern{0, 0, 0, 0};
112 break;
113 default:
114 ASSERT_MSG(false, "Invalid npad id type");
115 break;
116 }
117}
118
119void NpadAbstractLedHandler::SetLedBlinkingDevice(Core::HID::LedPattern pattern) {
120 led_blinking = pattern;
121}
122
123} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_led_handler.h b/src/hid_core/resources/abstracted_pad/abstract_led_handler.h
new file mode 100644
index 000000000..09528129b
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_led_handler.h
@@ -0,0 +1,43 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8#include "hid_core/hid_types.h"
9
10namespace Service::HID {
11struct AppletResourceHolder;
12class NpadAbstractedPadHolder;
13class NpadAbstractPropertiesHandler;
14
15/// Handles Npad request from HID interfaces
16class NpadAbstractLedHandler final {
17public:
18 explicit NpadAbstractLedHandler();
19 ~NpadAbstractLedHandler();
20
21 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
22 void SetAppletResource(AppletResourceHolder* applet_resource);
23 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
24
25 Result IncrementRefCounter();
26 Result DecrementRefCounter();
27
28 void SetNpadLedHandlerLedPattern();
29
30 void SetLedBlinkingDevice(Core::HID::LedPattern pattern);
31
32private:
33 AppletResourceHolder* applet_resource_holder{nullptr};
34 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
35 NpadAbstractPropertiesHandler* properties_handler{nullptr};
36
37 s32 ref_counter{};
38 Core::HID::LedPattern led_blinking{0, 0, 0, 0};
39 Core::HID::LedPattern left_pattern{0, 0, 0, 0};
40 Core::HID::LedPattern right_pattern{0, 0, 0, 0};
41 u64 led_interval{};
42};
43} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp
new file mode 100644
index 000000000..6f35bd95c
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.cpp
@@ -0,0 +1,108 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/abstracted_pad/abstract_mcu_handler.h"
6#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
7#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
8#include "hid_core/resources/npad/npad_types.h"
9
10namespace Service::HID {
11
12NpadAbstractMcuHandler::NpadAbstractMcuHandler() {}
13
14NpadAbstractMcuHandler::~NpadAbstractMcuHandler() = default;
15
16void NpadAbstractMcuHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
17 abstract_pad_holder = holder;
18}
19
20void NpadAbstractMcuHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
21 properties_handler = handler;
22}
23
24Result NpadAbstractMcuHandler::IncrementRefCounter() {
25 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
26 return ResultNpadHandlerOverflow;
27 }
28 ref_counter++;
29 return ResultSuccess;
30}
31
32Result NpadAbstractMcuHandler::DecrementRefCounter() {
33 if (ref_counter == 0) {
34 return ResultNpadHandlerNotInitialized;
35 }
36 ref_counter--;
37 return ResultSuccess;
38}
39
40void NpadAbstractMcuHandler::UpdateMcuState() {
41 std::array<IAbstractedPad*, 5> abstract_pads{};
42 const std::size_t count = properties_handler->GetAbstractedPads(abstract_pads);
43
44 if (count == 0) {
45 mcu_holder = {};
46 return;
47 }
48
49 for (std::size_t i = 0; i < count; i++) {
50 auto* abstract_pad = abstract_pads[i];
51 if (!abstract_pad->internal_flags.is_connected) {
52 continue;
53 }
54 if (!abstract_pad->disabled_feature_set.has_left_joy_rail_bus) {
55 if (!abstract_pad->disabled_feature_set.has_left_joy_six_axis_sensor &&
56 !abstract_pad->disabled_feature_set.has_right_joy_six_axis_sensor) {
57 continue;
58 }
59 if (mcu_holder[1].state != NpadMcuState::Active) {
60 mcu_holder[1].state = NpadMcuState::Available;
61 }
62 mcu_holder[1].abstracted_pad = abstract_pad;
63 continue;
64 }
65 if (mcu_holder[0].state != NpadMcuState::Active) {
66 mcu_holder[0].state = NpadMcuState::Available;
67 }
68 mcu_holder[0].abstracted_pad = abstract_pad;
69 }
70}
71
72Result NpadAbstractMcuHandler::GetAbstractedPad(IAbstractedPad** data, u32 mcu_index) {
73 if (mcu_holder[mcu_index].state == NpadMcuState::None ||
74 mcu_holder[mcu_index].abstracted_pad == nullptr) {
75 return ResultMcuIsNotReady;
76 }
77 *data = mcu_holder[mcu_index].abstracted_pad;
78 return ResultSuccess;
79}
80
81NpadMcuState NpadAbstractMcuHandler::GetMcuState(u32 mcu_index) {
82 return mcu_holder[mcu_index].state;
83}
84
85Result NpadAbstractMcuHandler::SetMcuState(bool is_enabled, u32 mcu_index) {
86 NpadMcuState& state = mcu_holder[mcu_index].state;
87
88 if (state == NpadMcuState::None) {
89 return ResultMcuIsNotReady;
90 }
91
92 if ((is_enabled) && (state == NpadMcuState::Available)) {
93 state = NpadMcuState::Active;
94 return ResultSuccess;
95 }
96
97 if (is_enabled) {
98 return ResultSuccess;
99 }
100 if (state != NpadMcuState::Active) {
101 return ResultSuccess;
102 }
103
104 state = NpadMcuState::Available;
105 return ResultSuccess;
106}
107
108} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h
new file mode 100644
index 000000000..9902dd03a
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_mcu_handler.h
@@ -0,0 +1,52 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8#include "hid_core/hid_types.h"
9
10namespace Service::HID {
11struct IAbstractedPad;
12class NpadAbstractedPadHolder;
13class NpadAbstractPropertiesHandler;
14
15enum class NpadMcuState : u32 {
16 None,
17 Available,
18 Active,
19};
20
21struct NpadMcuHolder {
22 NpadMcuState state;
23 INSERT_PADDING_BYTES(0x4);
24 IAbstractedPad* abstracted_pad;
25};
26static_assert(sizeof(NpadMcuHolder) == 0x10, "NpadMcuHolder is an invalid size");
27
28/// Handles Npad request from HID interfaces
29class NpadAbstractMcuHandler final {
30public:
31 explicit NpadAbstractMcuHandler();
32 ~NpadAbstractMcuHandler();
33
34 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
35 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
36
37 Result IncrementRefCounter();
38 Result DecrementRefCounter();
39
40 void UpdateMcuState();
41 Result GetAbstractedPad(IAbstractedPad** data, u32 mcu_index);
42 NpadMcuState GetMcuState(u32 mcu_index);
43 Result SetMcuState(bool is_enabled, u32 mcu_index);
44
45private:
46 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
47 NpadAbstractPropertiesHandler* properties_handler{nullptr};
48
49 s32 ref_counter{};
50 std::array<NpadMcuHolder, 2> mcu_holder{};
51};
52} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp
new file mode 100644
index 000000000..bd9b79333
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.cpp
@@ -0,0 +1,140 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/kernel/k_event.h"
5#include "core/hle/kernel/k_readable_event.h"
6#include "hid_core/hid_result.h"
7#include "hid_core/resources/abstracted_pad/abstract_nfc_handler.h"
8#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
9#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
10#include "hid_core/resources/npad/npad_types.h"
11
12namespace Service::HID {
13
14NpadAbstractNfcHandler::NpadAbstractNfcHandler() {}
15
16NpadAbstractNfcHandler::~NpadAbstractNfcHandler() = default;
17
18void NpadAbstractNfcHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
19 abstract_pad_holder = holder;
20}
21
22void NpadAbstractNfcHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
23 properties_handler = handler;
24}
25
26Result NpadAbstractNfcHandler::IncrementRefCounter() {
27 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
28 return ResultNpadHandlerOverflow;
29 }
30 ref_counter++;
31 return ResultSuccess;
32}
33
34Result NpadAbstractNfcHandler::DecrementRefCounter() {
35 if (ref_counter == 0) {
36 return ResultNpadHandlerNotInitialized;
37 }
38 ref_counter--;
39 return ResultSuccess;
40}
41
42void NpadAbstractNfcHandler::UpdateNfcState() {
43 std::array<IAbstractedPad*, 5> abstract_pads{};
44 const std::size_t count = properties_handler->GetAbstractedPads(abstract_pads);
45
46 if (count == 0) {
47 if (sensor_state == NpadNfcState::Active) {
48 nfc_activate_event->Signal();
49 }
50 if (sensor_state == NpadNfcState::Unavailable) {
51 return;
52 }
53 sensor_state = NpadNfcState::Unavailable;
54 input_event->Signal();
55 return;
56 }
57
58 bool is_found{};
59 for (std::size_t i = 0; i < count; i++) {
60 auto* abstract_pad = abstract_pads[i];
61 if (!abstract_pad->internal_flags.is_connected) {
62 continue;
63 }
64 if (!abstract_pad->disabled_feature_set.has_nfc) {
65 continue;
66 }
67 is_found = true;
68 xcd_handle = 0;
69 }
70
71 if (is_found) {
72 if (sensor_state == NpadNfcState::Active) {
73 return;
74 }
75 if (sensor_state == NpadNfcState::Available) {
76 return;
77 }
78 sensor_state = NpadNfcState::Available;
79 input_event->Signal();
80 return;
81 }
82
83 if (sensor_state == NpadNfcState::Active) {
84 nfc_activate_event->Signal();
85 }
86 if (sensor_state == NpadNfcState::Unavailable) {
87 return;
88 }
89 sensor_state = NpadNfcState::Unavailable;
90 input_event->Signal();
91 return;
92}
93
94bool NpadAbstractNfcHandler::HasNfcSensor() {
95 return sensor_state != NpadNfcState::Unavailable;
96}
97
98bool NpadAbstractNfcHandler::IsNfcActivated() {
99 return sensor_state == NpadNfcState::Active;
100}
101
102Result NpadAbstractNfcHandler::GetAcquireNfcActivateEventHandle(
103 Kernel::KReadableEvent** out_event) {
104 *out_event = &nfc_activate_event->GetReadableEvent();
105 return ResultSuccess;
106}
107
108void NpadAbstractNfcHandler::SetInputEvent(Kernel::KEvent* event) {
109 input_event = event;
110}
111
112Result NpadAbstractNfcHandler::ActivateNfc(bool is_enabled) {
113 if (sensor_state == NpadNfcState::Active) {
114 return ResultNfcIsNotReady;
115 }
116
117 NpadNfcState new_state = NpadNfcState::Available;
118 if (is_enabled) {
119 new_state = NpadNfcState::Active;
120 }
121 if (sensor_state != new_state) {
122 sensor_state = new_state;
123 nfc_activate_event->Signal();
124 }
125 return ResultSuccess;
126}
127
128Result NpadAbstractNfcHandler::GetXcdHandleWithNfc(u64& out_xcd_handle) const {
129 if (sensor_state == NpadNfcState::Unavailable) {
130 return ResultNfcIsNotReady;
131 }
132 if (xcd_handle == 0) {
133 return ResultNfcXcdHandleIsNotInitialized;
134 }
135
136 out_xcd_handle = xcd_handle;
137 return ResultSuccess;
138}
139
140} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h
new file mode 100644
index 000000000..0702722a6
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_nfc_handler.h
@@ -0,0 +1,57 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8#include "hid_core/hid_types.h"
9
10namespace Kernel {
11class KReadableEvent;
12}
13
14enum class NpadNfcState : u32 {
15 Unavailable,
16 Available,
17 Active,
18};
19
20namespace Service::HID {
21class NpadAbstractedPadHolder;
22class NpadAbstractPropertiesHandler;
23
24/// Handles Npad request from HID interfaces
25class NpadAbstractNfcHandler final {
26public:
27 explicit NpadAbstractNfcHandler();
28 ~NpadAbstractNfcHandler();
29
30 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
31 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
32
33 Result IncrementRefCounter();
34 Result DecrementRefCounter();
35
36 void UpdateNfcState();
37 bool HasNfcSensor();
38 bool IsNfcActivated();
39
40 Result GetAcquireNfcActivateEventHandle(Kernel::KReadableEvent** out_event);
41 void SetInputEvent(Kernel::KEvent* event);
42
43 Result ActivateNfc(bool is_enabled);
44
45 Result GetXcdHandleWithNfc(u64& out_xcd_handle) const;
46
47private:
48 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
49 NpadAbstractPropertiesHandler* properties_handler{nullptr};
50
51 s32 ref_counter{};
52 Kernel::KEvent* nfc_activate_event{nullptr};
53 Kernel::KEvent* input_event{nullptr};
54 u64 xcd_handle{};
55 NpadNfcState sensor_state{NpadNfcState::Unavailable};
56};
57} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp
new file mode 100644
index 000000000..2c7691d7c
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp
@@ -0,0 +1,294 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/abstracted_pad/abstract_pad.h"
6#include "hid_core/resources/applet_resource.h"
7#include "hid_core/resources/npad/npad_types.h"
8
9namespace Service::HID {
10
11AbstractPad::AbstractPad() {}
12
13AbstractPad::~AbstractPad() = default;
14
15void AbstractPad::SetExternals(AppletResourceHolder* applet_resource,
16 CaptureButtonResource* capture_button_resource,
17 HomeButtonResource* home_button_resource,
18 SixAxisResource* sixaxis_resource, PalmaResource* palma_resource,
19 VibrationHandler* vibration) {
20 applet_resource_holder = applet_resource;
21
22 properties_handler.SetAppletResource(applet_resource_holder);
23 properties_handler.SetAbstractPadHolder(&abstract_pad_holder);
24
25 led_handler.SetAppletResource(applet_resource_holder);
26 led_handler.SetAbstractPadHolder(&abstract_pad_holder);
27 led_handler.SetPropertiesHandler(&properties_handler);
28
29 ir_sensor_handler.SetAbstractPadHolder(&abstract_pad_holder);
30 ir_sensor_handler.SetPropertiesHandler(&properties_handler);
31
32 nfc_handler.SetAbstractPadHolder(&abstract_pad_holder);
33 nfc_handler.SetPropertiesHandler(&properties_handler);
34
35 mcu_handler.SetAbstractPadHolder(&abstract_pad_holder);
36 mcu_handler.SetPropertiesHandler(&properties_handler);
37
38 std::array<NpadVibrationDevice*, 2> vibration_devices{&vibration_left, &vibration_right};
39 vibration_handler.SetAppletResource(applet_resource_holder);
40 vibration_handler.SetAbstractPadHolder(&abstract_pad_holder);
41 vibration_handler.SetPropertiesHandler(&properties_handler);
42 vibration_handler.SetN64Vibration(&vibration_n64);
43 vibration_handler.SetVibration(vibration_devices);
44 vibration_handler.SetGcVibration(&vibration_gc);
45
46 sixaxis_handler.SetAppletResource(applet_resource_holder);
47 sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder);
48 sixaxis_handler.SetPropertiesHandler(&properties_handler);
49 sixaxis_handler.SetSixaxisResource(sixaxis_resource);
50
51 button_handler.SetAppletResource(applet_resource_holder);
52 button_handler.SetAbstractPadHolder(&abstract_pad_holder);
53 button_handler.SetPropertiesHandler(&properties_handler);
54
55 battery_handler.SetAppletResource(applet_resource_holder);
56 battery_handler.SetAbstractPadHolder(&abstract_pad_holder);
57 battery_handler.SetPropertiesHandler(&properties_handler);
58
59 palma_handler.SetAbstractPadHolder(&abstract_pad_holder);
60 palma_handler.SetPropertiesHandler(&properties_handler);
61 palma_handler.SetPalmaResource(palma_resource);
62}
63
64void AbstractPad::SetNpadId(Core::HID::NpadIdType npad_id) {
65 properties_handler.SetNpadId(npad_id);
66}
67
68Result AbstractPad::Activate() {
69 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
70 return ResultNpadHandlerOverflow;
71 }
72
73 if (ref_counter != 0) {
74 ref_counter++;
75 return ResultSuccess;
76 }
77
78 std::size_t stage = 0;
79 Result result = ResultSuccess;
80
81 if (result.IsSuccess()) {
82 stage++;
83 result = properties_handler.IncrementRefCounter();
84 }
85 if (result.IsSuccess()) {
86 stage++;
87 result = led_handler.IncrementRefCounter();
88 }
89 if (result.IsSuccess()) {
90 stage++;
91 result = ir_sensor_handler.IncrementRefCounter();
92 }
93 if (result.IsSuccess()) {
94 stage++;
95 result = mcu_handler.IncrementRefCounter();
96 }
97 if (result.IsSuccess()) {
98 stage++;
99 result = nfc_handler.IncrementRefCounter();
100 }
101 if (result.IsSuccess()) {
102 stage++;
103 result = vibration_handler.IncrementRefCounter();
104 }
105 if (result.IsSuccess()) {
106 stage++;
107 result = sixaxis_handler.IncrementRefCounter();
108 }
109 if (result.IsSuccess()) {
110 stage++;
111 result = button_handler.IncrementRefCounter();
112 }
113 if (result.IsSuccess()) {
114 stage++;
115 result = battery_handler.IncrementRefCounter();
116 }
117 if (result.IsSuccess()) {
118 stage++;
119 result = palma_handler.IncrementRefCounter();
120 }
121
122 if (result.IsSuccess()) {
123 ref_counter++;
124 return result;
125 }
126
127 if (stage > 9) {
128 battery_handler.DecrementRefCounter();
129 }
130 if (stage > 8) {
131 button_handler.DecrementRefCounter();
132 }
133 if (stage > 7) {
134 sixaxis_handler.DecrementRefCounter();
135 }
136 if (stage > 6) {
137 vibration_handler.DecrementRefCounter();
138 }
139 if (stage > 5) {
140 nfc_handler.DecrementRefCounter();
141 }
142 if (stage > 4) {
143 mcu_handler.DecrementRefCounter();
144 }
145 if (stage > 3) {
146 ir_sensor_handler.DecrementRefCounter();
147 }
148 if (stage > 2) {
149 led_handler.DecrementRefCounter();
150 }
151 if (stage > 1) {
152 properties_handler.DecrementRefCounter();
153 }
154 return result;
155}
156
157Result AbstractPad::Deactivate() {
158 if (ref_counter == 0) {
159 return ResultNpadResourceNotInitialized;
160 }
161
162 ref_counter--;
163 battery_handler.DecrementRefCounter();
164 button_handler.DecrementRefCounter();
165 sixaxis_handler.DecrementRefCounter();
166 vibration_handler.DecrementRefCounter();
167 nfc_handler.DecrementRefCounter();
168 ir_sensor_handler.DecrementRefCounter();
169 mcu_handler.DecrementRefCounter();
170 led_handler.DecrementRefCounter();
171 properties_handler.DecrementRefCounter();
172 palma_handler.DecrementRefCounter();
173
174 return ResultSuccess;
175}
176
177Result AbstractPad::ActivateNpad(u64 aruid) {
178 Result result = ResultSuccess;
179 if (result.IsSuccess()) {
180 result = properties_handler.ActivateNpadUnknown0x88(aruid);
181 }
182 if (result.IsSuccess()) {
183 result = sixaxis_handler.UpdateSixAxisState2(aruid);
184 }
185 if (result.IsSuccess()) {
186 result = battery_handler.UpdateBatteryState(aruid);
187 }
188 return result;
189}
190
191NpadAbstractedPadHolder* AbstractPad::GetAbstractedPadHolder() {
192 return &abstract_pad_holder;
193}
194
195NpadAbstractPropertiesHandler* AbstractPad::GetAbstractPropertiesHandler() {
196 return &properties_handler;
197}
198
199NpadAbstractLedHandler* AbstractPad::GetAbstractLedHandler() {
200 return &led_handler;
201}
202
203NpadAbstractIrSensorHandler* AbstractPad::GetAbstractIrSensorHandler() {
204 return &ir_sensor_handler;
205}
206
207NpadAbstractMcuHandler* AbstractPad::GetAbstractMcuHandler() {
208 return &mcu_handler;
209}
210
211NpadAbstractNfcHandler* AbstractPad::GetAbstractNfcHandler() {
212 return &nfc_handler;
213}
214
215NpadAbstractVibrationHandler* AbstractPad::GetAbstractVibrationHandler() {
216 return &vibration_handler;
217}
218
219NpadAbstractSixAxisHandler* AbstractPad::GetAbstractSixAxisHandler() {
220 return &sixaxis_handler;
221}
222
223NpadAbstractButtonHandler* AbstractPad::GetAbstractButtonHandler() {
224 return &button_handler;
225}
226
227NpadAbstractBatteryHandler* AbstractPad::GetAbstractBatteryHandler() {
228 return &battery_handler;
229}
230
231NpadN64VibrationDevice* AbstractPad::GetN64VibrationDevice() {
232 return &vibration_n64;
233}
234
235NpadVibrationDevice* AbstractPad::GetVibrationDevice(Core::HID::DeviceIndex device_index) {
236 if (device_index == Core::HID::DeviceIndex::Right) {
237 return &vibration_right;
238 }
239 return &vibration_left;
240}
241
242void AbstractPad::GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list) {
243 list.emplace_back(&vibration_left);
244 list.emplace_back(&vibration_right);
245}
246
247NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() {
248 return &vibration_gc;
249}
250
251Core::HID::NpadIdType AbstractPad::GetLastActiveNpad() {
252 return properties_handler.GetNpadId();
253}
254
255void AbstractPad::UpdateInterfaceType() {
256 if (interface_type != properties_handler.GetInterfaceType()) {
257 Update();
258 }
259 battery_handler.UpdateBatteryState();
260}
261
262void AbstractPad::Update() {
263 properties_handler.UpdateDeviceType();
264 led_handler.SetNpadLedHandlerLedPattern();
265 vibration_handler.UpdateVibrationState();
266 sixaxis_handler.UpdateSixAxisState();
267 nfc_handler.UpdateNfcState();
268 ir_sensor_handler.UpdateIrSensorState();
269 mcu_handler.UpdateMcuState();
270 palma_handler.UpdatePalmaState();
271 battery_handler.UpdateBatteryState();
272 button_handler.EnableCenterClamp();
273
274 interface_type = properties_handler.GetInterfaceType();
275
276 std::scoped_lock lock{*applet_resource_holder->shared_mutex};
277 properties_handler.UpdateAllDeviceProperties();
278 battery_handler.UpdateCoreBatteryState();
279 button_handler.UpdateCoreBatteryState();
280}
281
282void AbstractPad::UpdatePadState() {
283 button_handler.UpdateAllButtonLifo();
284 sixaxis_handler.UpdateSixAxisState();
285 battery_handler.UpdateCoreBatteryState();
286}
287
288void AbstractPad::EnableAppletToGetInput(u64 aruid) {
289 button_handler.UpdateButtonState(aruid);
290 sixaxis_handler.UpdateSixAxisState(aruid);
291 battery_handler.UpdateBatteryState(aruid);
292}
293
294} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.h b/src/hid_core/resources/abstracted_pad/abstract_pad.h
new file mode 100644
index 000000000..cbdf84af7
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_pad.h
@@ -0,0 +1,123 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <mutex>
8
9#include "common/common_types.h"
10#include "core/hle/result.h"
11#include "hid_core/hid_types.h"
12#include "hid_core/resources/applet_resource.h"
13#include "hid_core/resources/npad/npad_types.h"
14
15#include "hid_core/resources/abstracted_pad/abstract_battery_handler.h"
16#include "hid_core/resources/abstracted_pad/abstract_button_handler.h"
17#include "hid_core/resources/abstracted_pad/abstract_ir_sensor_handler.h"
18#include "hid_core/resources/abstracted_pad/abstract_led_handler.h"
19#include "hid_core/resources/abstracted_pad/abstract_mcu_handler.h"
20#include "hid_core/resources/abstracted_pad/abstract_nfc_handler.h"
21#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
22#include "hid_core/resources/abstracted_pad/abstract_palma_handler.h"
23#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
24#include "hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h"
25#include "hid_core/resources/abstracted_pad/abstract_vibration_handler.h"
26#include "hid_core/resources/vibration/gc_vibration_device.h"
27#include "hid_core/resources/vibration/n64_vibration_device.h"
28#include "hid_core/resources/vibration/vibration_device.h"
29
30namespace Service::HID {
31class AppletResource;
32class SixAxisResource;
33class PalmaResource;
34class NPadResource;
35class AbstractPad;
36class NpadLastActiveHandler;
37class NpadIrNfcHandler;
38class UniquePads;
39class NpadPalmaHandler;
40class FirmwareResource;
41class NpadVibration;
42class NpadHighestBattery;
43class NpadGcVibration;
44
45class CaptureButtonResource;
46class HomeButtonResource;
47class VibrationHandler;
48
49struct HandheldConfig;
50
51/// Handles Npad request from HID interfaces
52class AbstractPad final {
53public:
54 explicit AbstractPad();
55 ~AbstractPad();
56
57 void SetExternals(AppletResourceHolder* applet_resource,
58 CaptureButtonResource* capture_button_resource,
59 HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource,
60 PalmaResource* palma_resource, VibrationHandler* vibration);
61 void SetNpadId(Core::HID::NpadIdType npad_id);
62
63 Result Activate();
64 Result Deactivate();
65
66 Result ActivateNpad(u64 aruid);
67
68 NpadAbstractedPadHolder* GetAbstractedPadHolder();
69 NpadAbstractPropertiesHandler* GetAbstractPropertiesHandler();
70 NpadAbstractLedHandler* GetAbstractLedHandler();
71 NpadAbstractIrSensorHandler* GetAbstractIrSensorHandler();
72 NpadAbstractMcuHandler* GetAbstractMcuHandler();
73 NpadAbstractNfcHandler* GetAbstractNfcHandler();
74 NpadAbstractVibrationHandler* GetAbstractVibrationHandler();
75 NpadAbstractSixAxisHandler* GetAbstractSixAxisHandler();
76 NpadAbstractButtonHandler* GetAbstractButtonHandler();
77 NpadAbstractBatteryHandler* GetAbstractBatteryHandler();
78
79 NpadN64VibrationDevice* GetN64VibrationDevice();
80 NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index);
81 void GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list);
82 NpadGcVibrationDevice* GetGCVibrationDevice();
83
84 Core::HID::NpadIdType GetLastActiveNpad();
85 void UpdateInterfaceType();
86 void Update();
87
88 void UpdatePadState();
89 void EnableAppletToGetInput(u64 aruid);
90
91private:
92 AppletResourceHolder* applet_resource_holder{nullptr};
93 NpadAbstractedPadHolder abstract_pad_holder{};
94 NpadAbstractPropertiesHandler properties_handler{};
95 NpadAbstractLedHandler led_handler{};
96 NpadAbstractIrSensorHandler ir_sensor_handler{};
97 NpadAbstractNfcHandler nfc_handler{};
98 NpadAbstractMcuHandler mcu_handler{};
99 NpadAbstractVibrationHandler vibration_handler{};
100 NpadAbstractSixAxisHandler sixaxis_handler{};
101 NpadAbstractButtonHandler button_handler{};
102 NpadAbstractBatteryHandler battery_handler{};
103 NpadAbstractPalmaHandler palma_handler{};
104
105 NpadN64VibrationDevice vibration_n64{};
106 NpadVibrationDevice vibration_left{};
107 NpadVibrationDevice vibration_right{};
108 NpadGcVibrationDevice vibration_gc{};
109
110 // SixAxisConfigHolder fullkey_config;
111 // SixAxisConfigHolder handheld_config;
112 // SixAxisConfigHolder dual_left_config;
113 // SixAxisConfigHolder dual_right_config;
114 // SixAxisConfigHolder left_config;
115 // SixAxisConfigHolder right_config;
116
117 s32 ref_counter{};
118 Core::HID::NpadInterfaceType interface_type{Core::HID::NpadInterfaceType::None};
119};
120
121using FullAbstractPad = std::array<AbstractPad, MaxSupportedNpadIdTypes>;
122
123} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp
new file mode 100644
index 000000000..8334dc34f
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.cpp
@@ -0,0 +1,99 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
6#include "hid_core/resources/npad/npad_types.h"
7
8namespace Service::HID {
9
10Result NpadAbstractedPadHolder::RegisterAbstractPad(IAbstractedPad* abstracted_pad) {
11 if (list_size >= assignment_list.size()) {
12 return ResultNpadIsNotProController;
13 }
14
15 for (std::size_t i = 0; i < list_size; i++) {
16 if (assignment_list[i].device_type == abstracted_pad->device_type) {
17 return ResultNpadIsNotProController;
18 }
19 }
20
21 assignment_list[list_size] = {
22 .abstracted_pad = abstracted_pad,
23 .device_type = abstracted_pad->device_type,
24 .interface_type = abstracted_pad->interface_type,
25 .controller_id = abstracted_pad->controller_id,
26 };
27
28 list_size++;
29 return ResultSuccess;
30}
31
32void NpadAbstractedPadHolder::RemoveAbstractPadByControllerId(u64 controller_id) {
33 if (list_size == 0) {
34 return;
35 }
36 if (controller_id == 0) {
37 return;
38 }
39 for (std::size_t i = 0; i < list_size; i++) {
40 if (assignment_list[i].controller_id != controller_id) {
41 continue;
42 }
43 for (std::size_t e = i + 1; e < list_size; e++) {
44 assignment_list[e - 1] = assignment_list[e];
45 }
46 list_size--;
47 return;
48 }
49}
50
51void NpadAbstractedPadHolder::DetachAbstractedPad() {
52 while (list_size > 0) {
53 for (std::size_t i = 1; i < list_size; i++) {
54 assignment_list[i - 1] = assignment_list[i];
55 }
56 list_size--;
57 }
58}
59
60u64 NpadAbstractedPadHolder::RemoveAbstractPadByAssignmentStyle(
61 Service::HID::AssignmentStyle assignment_style) {
62 for (std::size_t i = 0; i < list_size; i++) {
63 if ((assignment_style.raw & assignment_list[i].abstracted_pad->assignment_style.raw) == 0) {
64 continue;
65 }
66 for (std::size_t e = i + 1; e < list_size; e++) {
67 assignment_list[e - 1] = assignment_list[e];
68 }
69 list_size--;
70 return list_size;
71 }
72 return list_size;
73}
74
75u32 NpadAbstractedPadHolder::GetAbstractedPads(std::span<IAbstractedPad*> list) const {
76 u32 num_elements = std::min(static_cast<u32>(list.size()), list_size);
77 for (std::size_t i = 0; i < num_elements; i++) {
78 list[i] = assignment_list[i].abstracted_pad;
79 }
80 return num_elements;
81}
82
83void NpadAbstractedPadHolder::SetAssignmentMode(const NpadJoyAssignmentMode& mode) {
84 assignment_mode = mode;
85}
86
87NpadJoyAssignmentMode NpadAbstractedPadHolder::GetAssignmentMode() const {
88 return assignment_mode;
89}
90
91std::size_t NpadAbstractedPadHolder::GetStyleIndexList(
92 std::span<Core::HID::NpadStyleIndex> list) const {
93 for (std::size_t i = 0; i < list_size; i++) {
94 list[i] = assignment_list[i].device_type;
95 }
96 return list_size;
97}
98
99} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h
new file mode 100644
index 000000000..fb7f472e8
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_pad_holder.h
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <mutex>
8#include <span>
9
10#include "common/common_types.h"
11#include "core/hle/result.h"
12#include "hid_core/hid_types.h"
13#include "hid_core/resources/npad/npad_types.h"
14
15namespace Service::HID {
16struct IAbstractedPad;
17
18struct AbstractAssignmentHolder {
19 IAbstractedPad* abstracted_pad;
20 Core::HID::NpadStyleIndex device_type;
21 Core::HID::NpadInterfaceType interface_type;
22 INSERT_PADDING_BYTES(0x6);
23 u64 controller_id;
24};
25static_assert(sizeof(AbstractAssignmentHolder) == 0x18,
26 "AbstractAssignmentHolder is an invalid size");
27
28/// This is nn::hid::server::NpadAbstractedPadHolder
29class NpadAbstractedPadHolder final {
30public:
31 Result RegisterAbstractPad(IAbstractedPad* abstracted_pad);
32 void RemoveAbstractPadByControllerId(u64 controller_id);
33 void DetachAbstractedPad();
34 u64 RemoveAbstractPadByAssignmentStyle(Service::HID::AssignmentStyle assignment_style);
35 u32 GetAbstractedPads(std::span<IAbstractedPad*> list) const;
36
37 void SetAssignmentMode(const NpadJoyAssignmentMode& mode);
38 NpadJoyAssignmentMode GetAssignmentMode() const;
39
40 std::size_t GetStyleIndexList(std::span<Core::HID::NpadStyleIndex> list) const;
41
42private:
43 std::array<AbstractAssignmentHolder, 5> assignment_list{};
44 u32 list_size{};
45 NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
46};
47} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp
new file mode 100644
index 000000000..04d276d61
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.cpp
@@ -0,0 +1,47 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/abstracted_pad/abstract_palma_handler.h"
6#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
7
8namespace Service::HID {
9
10NpadAbstractPalmaHandler::NpadAbstractPalmaHandler() {}
11
12NpadAbstractPalmaHandler::~NpadAbstractPalmaHandler() = default;
13
14void NpadAbstractPalmaHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
15 abstract_pad_holder = holder;
16}
17
18void NpadAbstractPalmaHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
19 properties_handler = handler;
20 return;
21}
22
23void NpadAbstractPalmaHandler::SetPalmaResource(PalmaResource* resource) {
24 palma_resource = resource;
25}
26
27Result NpadAbstractPalmaHandler::IncrementRefCounter() {
28 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
29 return ResultNpadHandlerOverflow;
30 }
31 ref_counter++;
32 return ResultSuccess;
33}
34
35Result NpadAbstractPalmaHandler::DecrementRefCounter() {
36 if (ref_counter == 0) {
37 return ResultNpadHandlerNotInitialized;
38 }
39 ref_counter--;
40 return ResultSuccess;
41}
42
43void NpadAbstractPalmaHandler::UpdatePalmaState() {
44 // TODO
45}
46
47} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h
new file mode 100644
index 000000000..fbd2e67e5
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_palma_handler.h
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8#include "hid_core/hid_types.h"
9
10namespace Service::HID {
11class NpadAbstractedPadHolder;
12class NpadAbstractPropertiesHandler;
13class PalmaResource;
14
15class NpadAbstractPalmaHandler final {
16public:
17 explicit NpadAbstractPalmaHandler();
18 ~NpadAbstractPalmaHandler();
19
20 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
21 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
22 void SetPalmaResource(PalmaResource* resource);
23
24 Result IncrementRefCounter();
25 Result DecrementRefCounter();
26
27 void UpdatePalmaState();
28
29private:
30 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
31 NpadAbstractPropertiesHandler* properties_handler{nullptr};
32 PalmaResource* palma_resource{nullptr};
33
34 s32 ref_counter{};
35};
36
37} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp
new file mode 100644
index 000000000..4897a2784
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.cpp
@@ -0,0 +1,322 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_util.h"
5#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
6#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
7#include "hid_core/resources/applet_resource.h"
8#include "hid_core/resources/npad/npad_resource.h"
9#include "hid_core/resources/npad/npad_types.h"
10#include "hid_core/resources/shared_memory_format.h"
11
12namespace Service::HID {
13
14NpadAbstractPropertiesHandler::NpadAbstractPropertiesHandler() {}
15
16NpadAbstractPropertiesHandler::~NpadAbstractPropertiesHandler() = default;
17
18void NpadAbstractPropertiesHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
19 abstract_pad_holder = holder;
20 return;
21}
22
23void NpadAbstractPropertiesHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
24 applet_resource_holder = applet_resource;
25 return;
26}
27
28void NpadAbstractPropertiesHandler::SetNpadId(Core::HID::NpadIdType npad_id) {
29 if (!IsNpadIdValid(npad_id)) {
30 ASSERT_MSG(false, "Invalid npad id");
31 }
32
33 npad_id_type = npad_id;
34}
35
36Core::HID::NpadIdType NpadAbstractPropertiesHandler::GetNpadId() const {
37 return npad_id_type;
38}
39
40Result NpadAbstractPropertiesHandler::IncrementRefCounter() {
41 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
42 return ResultNpadHandlerOverflow;
43 }
44
45 if (ref_counter != 0) {
46 ref_counter++;
47 return ResultSuccess;
48 }
49
50 const auto npad_index = NpadIdTypeToIndex(npad_id_type);
51 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
52 auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index);
53 auto& internal_state =
54 data->shared_memory_format->npad.npad_entry[npad_index].internal_state;
55 if (!data->flag.is_assigned) {
56 continue;
57 }
58 internal_state.fullkey_lifo.buffer_count = 0;
59 internal_state.handheld_lifo.buffer_count = 0;
60 internal_state.joy_dual_lifo.buffer_count = 0;
61 internal_state.joy_left_lifo.buffer_count = 0;
62 internal_state.joy_right_lifo.buffer_count = 0;
63 internal_state.palma_lifo.buffer_count = 0;
64 internal_state.system_ext_lifo.buffer_count = 0;
65 internal_state.gc_trigger_lifo.buffer_count = 0;
66 internal_state.sixaxis_fullkey_lifo.lifo.buffer_count = 0;
67 internal_state.sixaxis_handheld_lifo.lifo.buffer_count = 0;
68 internal_state.sixaxis_dual_left_lifo.lifo.buffer_count = 0;
69 internal_state.sixaxis_dual_right_lifo.lifo.buffer_count = 0;
70 internal_state.sixaxis_left_lifo.lifo.buffer_count = 0;
71 internal_state.sixaxis_right_lifo.lifo.buffer_count = 0;
72
73 internal_state.style_tag = {Core::HID::NpadStyleSet::None};
74 internal_state.assignment_mode = NpadJoyAssignmentMode::Dual;
75 internal_state.joycon_color = {};
76 internal_state.fullkey_color = {};
77
78 internal_state.system_properties.raw = 0;
79 internal_state.button_properties.raw = 0;
80 internal_state.device_type.raw = 0;
81
82 internal_state.battery_level_dual = Core::HID::NpadBatteryLevel::Empty;
83 internal_state.battery_level_left = Core::HID::NpadBatteryLevel::Empty;
84 internal_state.battery_level_right = Core::HID::NpadBatteryLevel::Empty;
85
86 internal_state.applet_footer_type = AppletFooterUiType::None;
87 internal_state.applet_footer_attributes = {};
88 internal_state.lark_type_l_and_main = {};
89 internal_state.lark_type_r = {};
90
91 internal_state.sixaxis_fullkey_properties.is_newly_assigned.Assign(true);
92 internal_state.sixaxis_handheld_properties.is_newly_assigned.Assign(true);
93 internal_state.sixaxis_dual_left_properties.is_newly_assigned.Assign(true);
94 internal_state.sixaxis_dual_right_properties.is_newly_assigned.Assign(true);
95 internal_state.sixaxis_left_properties.is_newly_assigned.Assign(true);
96 internal_state.sixaxis_right_properties.is_newly_assigned.Assign(true);
97 }
98
99 ref_counter++;
100 return ResultSuccess;
101}
102
103Result NpadAbstractPropertiesHandler::DecrementRefCounter() {
104 if (ref_counter == 0) {
105 return ResultNpadHandlerNotInitialized;
106 }
107 ref_counter--;
108 return ResultSuccess;
109}
110
111Result NpadAbstractPropertiesHandler::ActivateNpadUnknown0x88(u64 aruid) {
112 const auto npad_index = NpadIdTypeToIndex(npad_id_type);
113 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
114 auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index);
115 if (!data->flag.is_assigned || data->aruid != aruid) {
116 continue;
117 }
118 UpdateDeviceProperties(aruid, data->shared_memory_format->npad.npad_entry[npad_index]);
119 return ResultSuccess;
120 }
121 return ResultSuccess;
122}
123
124void NpadAbstractPropertiesHandler::UpdateDeviceType() {
125 // TODO
126}
127
128void NpadAbstractPropertiesHandler::UpdateDeviceColor() {
129 // TODO
130}
131
132void NpadAbstractPropertiesHandler::UpdateFooterAttributes() {
133 // TODO
134}
135
136void NpadAbstractPropertiesHandler::UpdateAllDeviceProperties() {
137 const auto npad_index = NpadIdTypeToIndex(npad_id_type);
138 for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) {
139 auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid_index);
140 if (!data->flag.is_assigned) {
141 continue;
142 }
143 auto& npad_entry = data->shared_memory_format->npad.npad_entry[npad_index];
144 UpdateDeviceProperties(data->aruid, npad_entry);
145 }
146}
147
148Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetFullkeyInterfaceType() {
149 std::array<IAbstractedPad*, 5> abstract_pads{};
150 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
151
152 for (std::size_t i = 0; i < count; i++) {
153 auto* abstract_pad = abstract_pads[i];
154 if (!abstract_pad->internal_flags.is_connected) {
155 continue;
156 }
157 if (abstract_pad->device_type != Core::HID::NpadStyleIndex::Fullkey) {
158 continue;
159 }
160 if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) {
161 // Abort
162 continue;
163 }
164 return abstract_pad->interface_type;
165 }
166
167 return Core::HID::NpadInterfaceType::None;
168}
169
170Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetInterfaceType() {
171 std::array<IAbstractedPad*, 5> abstract_pads{};
172 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
173
174 for (std::size_t i = 0; i < count; i++) {
175 auto* abstract_pad = abstract_pads[i];
176 if (!abstract_pad->internal_flags.is_connected) {
177 continue;
178 }
179 if (!abstract_pad->disabled_feature_set.has_identification_code) {
180 continue;
181 }
182 if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) {
183 // Abort
184 continue;
185 }
186 return abstract_pad->interface_type;
187 }
188 return Core::HID::NpadInterfaceType::None;
189}
190
191Core::HID::NpadStyleSet NpadAbstractPropertiesHandler::GetStyleSet(u64 aruid) {
192 // TODO
193 return Core::HID::NpadStyleSet::None;
194}
195
196std::size_t NpadAbstractPropertiesHandler::GetAbstractedPadsWithStyleTag(
197 std::span<IAbstractedPad*> list, Core::HID::NpadStyleTag style) {
198 std::array<IAbstractedPad*, 5> abstract_pads{};
199 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
200
201 if (count == 0) {
202 return count;
203 }
204
205 bool is_supported_style_set{};
206 const auto result = applet_resource_holder->shared_npad_resource->IsSupportedNpadStyleSet(
207 is_supported_style_set, applet_resource_holder->applet_resource->GetActiveAruid());
208
209 if (!is_supported_style_set || result.IsError()) {
210 for (std::size_t i = 0; i < count; i++) {
211 // TODO
212 }
213 return count;
214 }
215
216 std::size_t filtered_count{};
217 for (std::size_t i = 0; i < count; i++) {
218 auto* abstract_pad = abstract_pads[i];
219 const bool is_enabled = true;
220 if (is_enabled) {
221 list[filtered_count] = abstract_pad;
222 filtered_count++;
223 }
224 }
225
226 return filtered_count;
227}
228
229std::size_t NpadAbstractPropertiesHandler::GetAbstractedPads(std::span<IAbstractedPad*> list) {
230 Core::HID::NpadStyleTag style{
231 GetStyleSet(applet_resource_holder->applet_resource->GetActiveAruid())};
232 return GetAbstractedPadsWithStyleTag(list, style);
233}
234
235AppletFooterUiType NpadAbstractPropertiesHandler::GetAppletFooterUiType() {
236 return applet_ui_type.footer;
237}
238
239AppletDetailedUiType NpadAbstractPropertiesHandler::GetAppletDetailedUiType() {
240 return applet_ui_type;
241}
242
243void NpadAbstractPropertiesHandler::UpdateDeviceProperties(u64 aruid,
244 NpadSharedMemoryEntry& internal_state) {
245 // TODO
246}
247
248Core::HID::NpadInterfaceType NpadAbstractPropertiesHandler::GetNpadInterfaceType() {
249 std::array<IAbstractedPad*, 5> abstract_pads{};
250 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
251
252 for (std::size_t i = 0; i < count; i++) {
253 auto* abstract_pad = abstract_pads[i];
254 if (!abstract_pad->internal_flags.is_connected) {
255 continue;
256 }
257 if (abstract_pad->interface_type >= Core::HID::NpadInterfaceType::Embedded) {
258 // Abort
259 continue;
260 }
261 return abstract_pad->interface_type;
262 }
263
264 return Core::HID::NpadInterfaceType::None;
265}
266
267Result NpadAbstractPropertiesHandler::GetNpadFullKeyGripColor(
268 Core::HID::NpadColor& main_color, Core::HID::NpadColor& sub_color) const {
269 std::array<IAbstractedPad*, 5> abstract_pads{};
270 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
271
272 if (applet_ui_type.footer != AppletFooterUiType::SwitchProController) {
273 return ResultNpadIsNotProController;
274 }
275
276 for (std::size_t i = 0; i < count; i++) {
277 auto* abstract_pad = abstract_pads[i];
278 if (!abstract_pad->internal_flags.is_connected) {
279 continue;
280 }
281 return ResultSuccess;
282 }
283
284 return ResultNpadIsNotProController;
285}
286
287void NpadAbstractPropertiesHandler::GetNpadLeftRightInterfaceType(
288 Core::HID::NpadInterfaceType& out_left_interface,
289 Core::HID::NpadInterfaceType& out_right_interface) const {
290 out_left_interface = Core::HID::NpadInterfaceType::None;
291 out_right_interface = Core::HID::NpadInterfaceType::None;
292
293 std::array<IAbstractedPad*, 5> abstract_pads{};
294 const std::size_t count = abstract_pad_holder->GetAbstractedPads(abstract_pads);
295
296 for (std::size_t i = 0; i < count; i++) {
297 auto* abstract_pad = abstract_pads[i];
298 if (!abstract_pad->internal_flags.is_connected) {
299 continue;
300 }
301 if (abstract_pad->assignment_style.is_external_left_assigned &&
302 abstract_pad->assignment_style.is_handheld_left_assigned) {
303 if (abstract_pad->interface_type > Core::HID::NpadInterfaceType::Embedded) {
304 // Abort
305 continue;
306 }
307 out_left_interface = abstract_pad->interface_type;
308 continue;
309 }
310 if (abstract_pad->assignment_style.is_external_right_assigned &&
311 abstract_pad->assignment_style.is_handheld_right_assigned) {
312 if (abstract_pad->interface_type > Core::HID::NpadInterfaceType::Embedded) {
313 // Abort
314 continue;
315 }
316 out_right_interface = abstract_pad->interface_type;
317 continue;
318 }
319 }
320}
321
322} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h
new file mode 100644
index 000000000..fa6827899
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_properties_handler.h
@@ -0,0 +1,86 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <span>
7
8#include "common/common_types.h"
9#include "core/hle/result.h"
10#include "hid_core/hid_types.h"
11#include "hid_core/resources/npad/npad_types.h"
12
13namespace Service::HID {
14struct NpadSharedMemoryEntry;
15
16struct AppletResourceHolder;
17class NpadAbstractedPadHolder;
18
19struct ColorProperties {
20 ColorAttribute attribute;
21 Core::HID::NpadControllerColor color;
22 INSERT_PADDING_BYTES(0x4);
23};
24
25/// Handles Npad request from HID interfaces
26class NpadAbstractPropertiesHandler final {
27public:
28 explicit NpadAbstractPropertiesHandler();
29 ~NpadAbstractPropertiesHandler();
30
31 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
32 void SetAppletResource(AppletResourceHolder* applet_resource);
33 void SetNpadId(Core::HID::NpadIdType npad_id);
34
35 Core::HID::NpadIdType GetNpadId() const;
36
37 Result IncrementRefCounter();
38 Result DecrementRefCounter();
39
40 Result ActivateNpadUnknown0x88(u64 aruid);
41
42 void UpdateDeviceType();
43 void UpdateDeviceColor();
44 void UpdateFooterAttributes();
45 void UpdateAllDeviceProperties();
46
47 Core::HID::NpadInterfaceType GetFullkeyInterfaceType();
48 Core::HID::NpadInterfaceType GetInterfaceType();
49
50 Core::HID::NpadStyleSet GetStyleSet(u64 aruid);
51 std::size_t GetAbstractedPadsWithStyleTag(std::span<IAbstractedPad*> list,
52 Core::HID::NpadStyleTag style);
53 std::size_t GetAbstractedPads(std::span<IAbstractedPad*> list);
54
55 AppletFooterUiType GetAppletFooterUiType();
56
57 AppletDetailedUiType GetAppletDetailedUiType();
58
59 void UpdateDeviceProperties(u64 aruid, NpadSharedMemoryEntry& internal_state);
60
61 Core::HID::NpadInterfaceType GetNpadInterfaceType();
62
63 Result GetNpadFullKeyGripColor(Core::HID::NpadColor& main_color,
64 Core::HID::NpadColor& sub_color) const;
65
66 void GetNpadLeftRightInterfaceType(Core::HID::NpadInterfaceType& param_2,
67 Core::HID::NpadInterfaceType& param_3) const;
68
69private:
70 AppletResourceHolder* applet_resource_holder{nullptr};
71 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
72 Core::HID::NpadIdType npad_id_type{Core::HID::NpadIdType::Invalid};
73 s32 ref_counter{};
74 Core::HID::DeviceIndex device_type{};
75 AppletDetailedUiType applet_ui_type{};
76 AppletFooterUiAttributes applet_ui_attributes{};
77 bool is_vertical{};
78 bool is_horizontal{};
79 bool use_plus{};
80 bool use_minus{};
81 bool has_directional_buttons{};
82 ColorProperties fullkey_color{};
83 ColorProperties left_color{};
84 ColorProperties right_color{};
85};
86} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp
new file mode 100644
index 000000000..6d759298e
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.cpp
@@ -0,0 +1,154 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/hid_util.h"
6#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
7#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
8#include "hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h"
9#include "hid_core/resources/applet_resource.h"
10#include "hid_core/resources/npad/npad_types.h"
11#include "hid_core/resources/shared_memory_format.h"
12
13namespace Service::HID {
14
15NpadAbstractSixAxisHandler::NpadAbstractSixAxisHandler() {}
16
17NpadAbstractSixAxisHandler::~NpadAbstractSixAxisHandler() = default;
18
19void NpadAbstractSixAxisHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
20 abstract_pad_holder = holder;
21}
22
23void NpadAbstractSixAxisHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
24 applet_resource_holder = applet_resource;
25}
26
27void NpadAbstractSixAxisHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
28 properties_handler = handler;
29}
30
31void NpadAbstractSixAxisHandler::SetSixaxisResource(SixAxisResource* resource) {
32 six_axis_resource = resource;
33}
34
35Result NpadAbstractSixAxisHandler::IncrementRefCounter() {
36 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
37 return ResultNpadHandlerOverflow;
38 }
39 ref_counter++;
40 return ResultSuccess;
41}
42
43Result NpadAbstractSixAxisHandler::DecrementRefCounter() {
44 if (ref_counter == 0) {
45 return ResultNpadHandlerNotInitialized;
46 }
47 ref_counter--;
48 return ResultSuccess;
49}
50
51u64 NpadAbstractSixAxisHandler::IsFirmwareUpdateAvailable() {
52 // TODO
53 return false;
54}
55
56Result NpadAbstractSixAxisHandler::UpdateSixAxisState() {
57 Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
58 for (std::size_t i = 0; i < AruidIndexMax; i++) {
59 auto* data = applet_resource_holder->applet_resource->GetAruidDataByIndex(i);
60 if (data->flag.is_assigned) {
61 continue;
62 }
63 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
64 UpdateSixaxisInternalState(npad_entry, data->aruid,
65 data->flag.enable_six_axis_sensor.As<bool>());
66 }
67 return ResultSuccess;
68}
69
70Result NpadAbstractSixAxisHandler::UpdateSixAxisState(u64 aruid) {
71 Core::HID::NpadIdType npad_id = properties_handler->GetNpadId();
72 auto* data = applet_resource_holder->applet_resource->GetAruidData(aruid);
73 if (data == nullptr) {
74 return ResultSuccess;
75 }
76 auto& npad_entry = data->shared_memory_format->npad.npad_entry[NpadIdTypeToIndex(npad_id)];
77 UpdateSixaxisInternalState(npad_entry, data->aruid,
78 data->flag.enable_six_axis_sensor.As<bool>());
79 return ResultSuccess;
80}
81
82Result NpadAbstractSixAxisHandler::UpdateSixAxisState2(u64 aruid) {
83 const auto npad_index = NpadIdTypeToIndex(properties_handler->GetNpadId());
84 AruidData* aruid_data = applet_resource_holder->applet_resource->GetAruidData(aruid);
85 if (aruid_data == nullptr) {
86 return ResultSuccess;
87 }
88 auto& npad_internal_state = aruid_data->shared_memory_format->npad.npad_entry[npad_index];
89 UpdateSixaxisInternalState(npad_internal_state, aruid,
90 aruid_data->flag.enable_six_axis_sensor.As<bool>());
91 return ResultSuccess;
92}
93
94void NpadAbstractSixAxisHandler::UpdateSixaxisInternalState(NpadSharedMemoryEntry& npad_entry,
95 u64 aruid, bool is_sensor_enabled) {
96 const Core::HID::NpadStyleTag style_tag{properties_handler->GetStyleSet(aruid)};
97
98 if (!style_tag.palma) {
99 UpdateSixaxisFullkeyLifo(style_tag, npad_entry.internal_state.sixaxis_fullkey_lifo,
100 is_sensor_enabled);
101 } else {
102 UpdateSixAxisPalmaLifo(style_tag, npad_entry.internal_state.sixaxis_fullkey_lifo,
103 is_sensor_enabled);
104 }
105 UpdateSixaxisHandheldLifo(style_tag, npad_entry.internal_state.sixaxis_handheld_lifo,
106 is_sensor_enabled);
107 UpdateSixaxisDualLifo(style_tag, npad_entry.internal_state.sixaxis_dual_left_lifo,
108 is_sensor_enabled);
109 UpdateSixaxisDualLifo(style_tag, npad_entry.internal_state.sixaxis_dual_right_lifo,
110 is_sensor_enabled);
111 UpdateSixaxisLeftLifo(style_tag, npad_entry.internal_state.sixaxis_left_lifo,
112 is_sensor_enabled);
113 UpdateSixaxisRightLifo(style_tag, npad_entry.internal_state.sixaxis_right_lifo,
114 is_sensor_enabled);
115 // TODO: Set sixaxis properties
116}
117
118void NpadAbstractSixAxisHandler::UpdateSixaxisFullkeyLifo(Core::HID::NpadStyleTag style_tag,
119 NpadSixAxisSensorLifo& sensor_lifo,
120 bool is_sensor_enabled) {
121 // TODO
122}
123
124void NpadAbstractSixAxisHandler::UpdateSixAxisPalmaLifo(Core::HID::NpadStyleTag style_tag,
125 NpadSixAxisSensorLifo& sensor_lifo,
126 bool is_sensor_enabled) {
127 // TODO
128}
129
130void NpadAbstractSixAxisHandler::UpdateSixaxisHandheldLifo(Core::HID::NpadStyleTag style_tag,
131 NpadSixAxisSensorLifo& sensor_lifo,
132 bool is_sensor_enabled) {
133 // TODO
134}
135
136void NpadAbstractSixAxisHandler::UpdateSixaxisDualLifo(Core::HID::NpadStyleTag style_tag,
137 NpadSixAxisSensorLifo& sensor_lifo,
138 bool is_sensor_enabled) {
139 // TODO
140}
141
142void NpadAbstractSixAxisHandler::UpdateSixaxisLeftLifo(Core::HID::NpadStyleTag style_tag,
143 NpadSixAxisSensorLifo& sensor_lifo,
144 bool is_sensor_enabled) {
145 // TODO
146}
147
148void NpadAbstractSixAxisHandler::UpdateSixaxisRightLifo(Core::HID::NpadStyleTag style_tag,
149 NpadSixAxisSensorLifo& sensor_lifo,
150 bool is_sensor_enabled) {
151 // TODO
152}
153
154} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h
new file mode 100644
index 000000000..9c20459e9
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_sixaxis_handler.h
@@ -0,0 +1,61 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8#include "hid_core/hid_types.h"
9
10namespace Service::HID {
11class SixAxisResource;
12struct AppletResourceHolder;
13class NpadAbstractedPadHolder;
14class NpadAbstractPropertiesHandler;
15struct NpadSixAxisSensorLifo;
16
17/// Handles Npad request from HID interfaces
18class NpadAbstractSixAxisHandler final {
19public:
20 explicit NpadAbstractSixAxisHandler();
21 ~NpadAbstractSixAxisHandler();
22
23 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
24 void SetAppletResource(AppletResourceHolder* applet_resource);
25 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
26 void SetSixaxisResource(SixAxisResource* resource);
27
28 Result IncrementRefCounter();
29 Result DecrementRefCounter();
30
31 u64 IsFirmwareUpdateAvailable();
32
33 Result UpdateSixAxisState();
34 Result UpdateSixAxisState(u64 aruid);
35 Result UpdateSixAxisState2(u64 aruid);
36
37private:
38 void UpdateSixaxisInternalState(NpadSharedMemoryEntry& npad_entry, u64 aruid,
39 bool is_sensor_enabled);
40 void UpdateSixaxisFullkeyLifo(Core::HID::NpadStyleTag style_tag,
41 NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
42 void UpdateSixAxisPalmaLifo(Core::HID::NpadStyleTag style_tag,
43 NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
44 void UpdateSixaxisHandheldLifo(Core::HID::NpadStyleTag style_tag,
45 NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
46 void UpdateSixaxisDualLifo(Core::HID::NpadStyleTag style_tag,
47 NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
48 void UpdateSixaxisLeftLifo(Core::HID::NpadStyleTag style_tag,
49 NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
50 void UpdateSixaxisRightLifo(Core::HID::NpadStyleTag style_tag,
51 NpadSixAxisSensorLifo& sensor_lifo, bool is_sensor_enabled);
52
53 AppletResourceHolder* applet_resource_holder{nullptr};
54 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
55 NpadAbstractPropertiesHandler* properties_handler{nullptr};
56 SixAxisResource* six_axis_resource{nullptr};
57
58 s32 ref_counter{};
59};
60
61} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp
new file mode 100644
index 000000000..a00d6c9de
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.cpp
@@ -0,0 +1,73 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/hid_util.h"
6#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
7#include "hid_core/resources/abstracted_pad/abstract_properties_handler.h"
8#include "hid_core/resources/abstracted_pad/abstract_vibration_handler.h"
9#include "hid_core/resources/applet_resource.h"
10#include "hid_core/resources/npad/npad_vibration.h"
11#include "hid_core/resources/vibration/gc_vibration_device.h"
12#include "hid_core/resources/vibration/n64_vibration_device.h"
13#include "hid_core/resources/vibration/vibration_device.h"
14
15namespace Service::HID {
16
17NpadAbstractVibrationHandler::NpadAbstractVibrationHandler() {}
18
19NpadAbstractVibrationHandler::~NpadAbstractVibrationHandler() = default;
20
21void NpadAbstractVibrationHandler::SetAbstractPadHolder(NpadAbstractedPadHolder* holder) {
22 abstract_pad_holder = holder;
23}
24
25void NpadAbstractVibrationHandler::SetAppletResource(AppletResourceHolder* applet_resource) {
26 applet_resource_holder = applet_resource;
27}
28
29void NpadAbstractVibrationHandler::SetPropertiesHandler(NpadAbstractPropertiesHandler* handler) {
30 properties_handler = handler;
31}
32
33void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) {
34 n64_vibration_device = n64_device;
35}
36
37void NpadAbstractVibrationHandler::SetVibration(std::span<NpadVibrationDevice*> device) {
38 for (std::size_t i = 0; i < device.size() && i < vibration_device.size(); i++) {
39 vibration_device[i] = device[i];
40 }
41}
42
43void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) {
44 gc_vibration_device = gc_device;
45}
46
47Result NpadAbstractVibrationHandler::IncrementRefCounter() {
48 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
49 return ResultNpadHandlerOverflow;
50 }
51 ref_counter++;
52 return ResultSuccess;
53}
54
55Result NpadAbstractVibrationHandler::DecrementRefCounter() {
56 if (ref_counter == 0) {
57 return ResultNpadHandlerNotInitialized;
58 }
59 ref_counter--;
60 return ResultSuccess;
61}
62
63void NpadAbstractVibrationHandler::UpdateVibrationState() {
64 const bool is_handheld_hid_enabled =
65 applet_resource_holder->handheld_config->is_handheld_hid_enabled;
66 const bool is_force_handheld_style_vibration =
67 applet_resource_holder->handheld_config->is_force_handheld_style_vibration;
68
69 if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) {
70 // TODO
71 }
72}
73} // namespace Service::HID
diff --git a/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h
new file mode 100644
index 000000000..aeb07ce86
--- /dev/null
+++ b/src/hid_core/resources/abstracted_pad/abstract_vibration_handler.h
@@ -0,0 +1,51 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <span>
7
8#include "common/common_types.h"
9#include "core/hle/result.h"
10#include "hid_core/hid_types.h"
11
12namespace Service::HID {
13struct AppletResourceHolder;
14class NpadAbstractedPadHolder;
15class NpadAbstractPropertiesHandler;
16class NpadGcVibrationDevice;
17class NpadVibrationDevice;
18class NpadN64VibrationDevice;
19class NpadVibration;
20
21/// Keeps track of battery levels and updates npad battery shared memory values
22class NpadAbstractVibrationHandler final {
23public:
24 explicit NpadAbstractVibrationHandler();
25 ~NpadAbstractVibrationHandler();
26
27 void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
28 void SetAppletResource(AppletResourceHolder* applet_resource);
29 void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
30
31 void SetN64Vibration(NpadN64VibrationDevice* n64_device);
32 void SetVibration(std::span<NpadVibrationDevice*> device);
33 void SetGcVibration(NpadGcVibrationDevice* gc_device);
34
35 Result IncrementRefCounter();
36 Result DecrementRefCounter();
37
38 void UpdateVibrationState();
39
40private:
41 AppletResourceHolder* applet_resource_holder{nullptr};
42 NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
43 NpadAbstractPropertiesHandler* properties_handler{nullptr};
44
45 NpadN64VibrationDevice* n64_vibration_device{nullptr};
46 std::array<NpadVibrationDevice*, 2> vibration_device{};
47 NpadGcVibrationDevice* gc_vibration_device{nullptr};
48 NpadVibration* vibration_handler{nullptr};
49 s32 ref_counter{};
50};
51} // namespace Service::HID
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp
index 1f8a0f8ab..97537a2e2 100644
--- a/src/hid_core/resources/npad/npad.cpp
+++ b/src/hid_core/resources/npad/npad.cpp
@@ -193,7 +193,7 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) {
193 case Core::HID::NpadStyleIndex::None: 193 case Core::HID::NpadStyleIndex::None:
194 ASSERT(false); 194 ASSERT(false);
195 break; 195 break;
196 case Core::HID::NpadStyleIndex::ProController: 196 case Core::HID::NpadStyleIndex::Fullkey:
197 shared_memory->fullkey_color.attribute = ColorAttribute::Ok; 197 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
198 shared_memory->fullkey_color.fullkey = body_colors.fullkey; 198 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
199 shared_memory->battery_level_dual = battery_level.dual.battery_level; 199 shared_memory->battery_level_dual = battery_level.dual.battery_level;
@@ -491,7 +491,7 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
491 case Core::HID::NpadStyleIndex::None: 491 case Core::HID::NpadStyleIndex::None:
492 ASSERT(false); 492 ASSERT(false);
493 break; 493 break;
494 case Core::HID::NpadStyleIndex::ProController: 494 case Core::HID::NpadStyleIndex::Fullkey:
495 case Core::HID::NpadStyleIndex::NES: 495 case Core::HID::NpadStyleIndex::NES:
496 case Core::HID::NpadStyleIndex::SNES: 496 case Core::HID::NpadStyleIndex::SNES:
497 case Core::HID::NpadStyleIndex::N64: 497 case Core::HID::NpadStyleIndex::N64:
@@ -1292,7 +1292,7 @@ Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
1292 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) { 1292 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
1293 auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); 1293 auto& controller = GetControllerFromHandle(aruid, sixaxis_handle);
1294 switch (sixaxis_handle.npad_type) { 1294 switch (sixaxis_handle.npad_type) {
1295 case Core::HID::NpadStyleIndex::ProController: 1295 case Core::HID::NpadStyleIndex::Fullkey:
1296 case Core::HID::NpadStyleIndex::Pokeball: 1296 case Core::HID::NpadStyleIndex::Pokeball:
1297 return controller.shared_memory->sixaxis_fullkey_properties; 1297 return controller.shared_memory->sixaxis_fullkey_properties;
1298 case Core::HID::NpadStyleIndex::Handheld: 1298 case Core::HID::NpadStyleIndex::Handheld:
@@ -1315,7 +1315,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
1315 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { 1315 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
1316 const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle); 1316 const auto& controller = GetControllerFromHandle(aruid, sixaxis_handle);
1317 switch (sixaxis_handle.npad_type) { 1317 switch (sixaxis_handle.npad_type) {
1318 case Core::HID::NpadStyleIndex::ProController: 1318 case Core::HID::NpadStyleIndex::Fullkey:
1319 case Core::HID::NpadStyleIndex::Pokeball: 1319 case Core::HID::NpadStyleIndex::Pokeball:
1320 return controller.shared_memory->sixaxis_fullkey_properties; 1320 return controller.shared_memory->sixaxis_fullkey_properties;
1321 case Core::HID::NpadStyleIndex::Handheld: 1321 case Core::HID::NpadStyleIndex::Handheld:
diff --git a/src/hid_core/resources/npad/npad_data.cpp b/src/hid_core/resources/npad/npad_data.cpp
index c7e9760cb..29ad5cb08 100644
--- a/src/hid_core/resources/npad/npad_data.cpp
+++ b/src/hid_core/resources/npad/npad_data.cpp
@@ -151,7 +151,7 @@ Core::HID::NpadStyleSet NPadData::GetSupportedNpadStyleSet() const {
151bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const { 151bool NPadData::IsNpadStyleIndexSupported(Core::HID::NpadStyleIndex style_index) const {
152 Core::HID::NpadStyleTag style = {supported_npad_style_set}; 152 Core::HID::NpadStyleTag style = {supported_npad_style_set};
153 switch (style_index) { 153 switch (style_index) {
154 case Core::HID::NpadStyleIndex::ProController: 154 case Core::HID::NpadStyleIndex::Fullkey:
155 return style.fullkey.As<bool>(); 155 return style.fullkey.As<bool>();
156 case Core::HID::NpadStyleIndex::Handheld: 156 case Core::HID::NpadStyleIndex::Handheld:
157 return style.handheld.As<bool>(); 157 return style.handheld.As<bool>();
diff --git a/src/hid_core/resources/npad/npad_types.h b/src/hid_core/resources/npad/npad_types.h
index a02f9cf16..074dd40cf 100644
--- a/src/hid_core/resources/npad/npad_types.h
+++ b/src/hid_core/resources/npad/npad_types.h
@@ -252,4 +252,103 @@ enum class NpadLagerType : u32 {
252 U, 252 U,
253}; 253};
254 254
255// nn::hidtypes::FeatureType
256struct FeatureType {
257 union {
258 u64 raw{};
259 BitField<0, 1, u64> has_left_analog_stick;
260 BitField<1, 1, u64> has_right_analog_stick;
261 BitField<2, 1, u64> has_left_joy_six_axis_sensor;
262 BitField<3, 1, u64> has_right_joy_six_axis_sensor;
263 BitField<4, 1, u64> has_fullkey_joy_six_axis_sensor;
264 BitField<5, 1, u64> has_left_lra_vibration_device;
265 BitField<6, 1, u64> has_right_lra_vibration_device;
266 BitField<7, 1, u64> has_gc_vibration_device;
267 BitField<8, 1, u64> has_erm_vibration_device;
268 BitField<9, 1, u64> has_left_joy_rail_bus;
269 BitField<10, 1, u64> has_right_joy_rail_bus;
270 BitField<11, 1, u64> has_internal_bus;
271 BitField<12, 1, u64> is_palma;
272 BitField<13, 1, u64> has_nfc;
273 BitField<14, 1, u64> has_ir_sensor;
274 BitField<15, 1, u64> is_analog_stick_calibration_supported;
275 BitField<16, 1, u64> is_six_axis_Sensor_user_calibration_supported;
276 BitField<17, 1, u64> has_left_right_joy_battery;
277 BitField<18, 1, u64> has_fullkey_battery;
278 BitField<19, 1, u64> is_disconnect_controller_if_battery_none;
279 BitField<20, 1, u64> has_controller_color;
280 BitField<21, 1, u64> has_grip_color;
281 BitField<22, 1, u64> has_identification_code;
282 BitField<23, 1, u64> has_bluetooth_address;
283 BitField<24, 1, u64> has_mcu;
284 BitField<25, 1, u64> has_notification_led;
285 BitField<26, 1, u64> has_directional_buttons;
286 BitField<27, 1, u64> has_indicator_led;
287 BitField<28, 1, u64> is_button_config_embedded_supported;
288 BitField<29, 1, u64> is_button_config_full_supported;
289 BitField<30, 1, u64> is_button_config_left_supported;
290 BitField<31, 1, u64> is_button_config_right_supported;
291 BitField<32, 1, u64> is_usb_hid_device;
292 BitField<33, 1, u64> is_kuina_device;
293 BitField<34, 1, u64> is_direct_usb_to_bt_switching_device;
294 BitField<35, 1, u64> is_normalize_analog_stick_with_inner_cross;
295 };
296};
297static_assert(sizeof(FeatureType) == 8, "FeatureType is an invalid size");
298
299// This is nn::hid::AssignmentStyle
300struct AssignmentStyle {
301 union {
302 u32 raw{};
303 BitField<0, 1, u32> is_external_assigned;
304 BitField<1, 1, u32> is_external_left_assigned;
305 BitField<2, 1, u32> is_external_right_assigned;
306 BitField<3, 1, u32> is_handheld_assigned;
307 BitField<4, 1, u32> is_handheld_left_assigned;
308 BitField<5, 1, u32> is_handheld_right_assigned;
309 };
310};
311static_assert(sizeof(AssignmentStyle) == 4, "AssignmentStyle is an invalid size");
312
313// This is nn::hid::server::IAbstractedPad::InternalFlags
314struct InternalFlags {
315 union {
316 u32 raw{};
317 BitField<0, 1, u32> is_bound;
318 BitField<1, 1, u32> is_connected;
319 BitField<2, 1, u32> is_battery_low_ovln_required;
320 BitField<3, 1, u32> is_battery_low_ovln_delay_required;
321 BitField<4, 1, u32> is_sample_recieved;
322 BitField<5, 1, u32> is_virtual_input;
323 BitField<6, 1, u32> is_wired;
324 BitField<8, 1, u32> use_center_clamp;
325 BitField<9, 1, u32> has_virtual_six_axis_sensor_acceleration;
326 BitField<10, 1, u32> has_virtual_six_axis_sensor_angle;
327 BitField<11, 1, u32> is_debug_pad;
328 };
329};
330static_assert(sizeof(InternalFlags) == 4, "InternalFlags is an invalid size");
331
332/// This is nn::hid::server::IAbstractedPad
333struct IAbstractedPad {
334 InternalFlags internal_flags;
335 u64 controller_id;
336 u32 controller_number;
337 u64 low_battery_display_delay_time;
338 u64 low_battery_display_delay_interval;
339 FeatureType feature_set;
340 FeatureType disabled_feature_set;
341 AssignmentStyle assignment_style;
342 Core::HID::NpadStyleIndex device_type;
343 Core::HID::NpadInterfaceType interface_type;
344 Core::HID::NpadPowerInfo power_info;
345 u32 pad_state;
346 u32 button_mask;
347 u32 system_button_mask;
348 u8 indicator;
349 std::vector<f32> virtual_six_axis_sensor_acceleration;
350 std::vector<f32> virtual_six_axis_sensor_angle;
351 u64 xcd_handle;
352 u64 color;
353};
255} // namespace Service::HID 354} // namespace Service::HID
diff --git a/src/hid_core/resources/npad/npad_vibration.cpp b/src/hid_core/resources/npad/npad_vibration.cpp
new file mode 100644
index 000000000..3bdd55dec
--- /dev/null
+++ b/src/hid_core/resources/npad/npad_vibration.cpp
@@ -0,0 +1,80 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/npad/npad_vibration.h"
6
7namespace Service::HID {
8
9NpadVibration::NpadVibration() {}
10
11NpadVibration::~NpadVibration() = default;
12
13Result NpadVibration::Activate() {
14 std::scoped_lock lock{mutex};
15
16 const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
17 // if (master_volume < 0.0f || master_volume > 1.0f) {
18 // return ResultVibrationStrenghtOutOfRange;
19 // }
20
21 volume = master_volume;
22 return ResultSuccess;
23}
24
25Result NpadVibration::Deactivate() {
26 return ResultSuccess;
27}
28
29Result NpadVibration::SetVibrationMasterVolume(f32 master_volume) {
30 std::scoped_lock lock{mutex};
31
32 if (master_volume < 0.0f && master_volume > 1.0f) {
33 return ResultVibrationStrenghtOutOfRange;
34 }
35
36 volume = master_volume;
37 // nn::settings::system::SetVibrationMasterVolume(master_volume);
38
39 return ResultSuccess;
40}
41
42Result NpadVibration::GetVibrationVolume(f32& out_volume) const {
43 std::scoped_lock lock{mutex};
44 out_volume = volume;
45 return ResultSuccess;
46}
47
48Result NpadVibration::GetVibrationMasterVolume(f32& out_volume) const {
49 std::scoped_lock lock{mutex};
50
51 const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
52 // if (master_volume < 0.0f || master_volume > 1.0f) {
53 // return ResultVibrationStrenghtOutOfRange;
54 // }
55
56 out_volume = master_volume;
57 return ResultSuccess;
58}
59
60Result NpadVibration::BeginPermitVibrationSession(u64 aruid) {
61 std::scoped_lock lock{mutex};
62 session_aruid = aruid;
63 volume = 1.0;
64 return ResultSuccess;
65}
66
67Result NpadVibration::EndPermitVibrationSession() {
68 std::scoped_lock lock{mutex};
69
70 const f32 master_volume = 1.0f; // nn::settings::system::GetVibrationMasterVolume();
71 // if (master_volume < 0.0f || master_volume > 1.0f) {
72 // return ResultVibrationStrenghtOutOfRange;
73 // }
74
75 volume = master_volume;
76 session_aruid = 0;
77 return ResultSuccess;
78}
79
80} // namespace Service::HID
diff --git a/src/hid_core/resources/npad/npad_vibration.h b/src/hid_core/resources/npad/npad_vibration.h
new file mode 100644
index 000000000..0748aeffc
--- /dev/null
+++ b/src/hid_core/resources/npad/npad_vibration.h
@@ -0,0 +1,34 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <mutex>
7
8#include "common/common_types.h"
9#include "core/hle/result.h"
10
11namespace Service::HID {
12
13class NpadVibration final {
14public:
15 explicit NpadVibration();
16 ~NpadVibration();
17
18 Result Activate();
19 Result Deactivate();
20
21 Result SetVibrationMasterVolume(f32 master_volume);
22 Result GetVibrationVolume(f32& out_volume) const;
23 Result GetVibrationMasterVolume(f32& out_volume) const;
24
25 Result BeginPermitVibrationSession(u64 aruid);
26 Result EndPermitVibrationSession();
27
28private:
29 f32 volume{};
30 u64 session_aruid{};
31 mutable std::mutex mutex;
32};
33
34} // namespace Service::HID
diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp
index 8a9677c50..da12d2d5a 100644
--- a/src/hid_core/resources/six_axis/six_axis.cpp
+++ b/src/hid_core/resources/six_axis/six_axis.cpp
@@ -114,7 +114,7 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
114 case Core::HID::NpadStyleIndex::None: 114 case Core::HID::NpadStyleIndex::None:
115 ASSERT(false); 115 ASSERT(false);
116 break; 116 break;
117 case Core::HID::NpadStyleIndex::ProController: 117 case Core::HID::NpadStyleIndex::Fullkey:
118 set_motion_state(sixaxis_fullkey_state, motion_state[0]); 118 set_motion_state(sixaxis_fullkey_state, motion_state[0]);
119 break; 119 break;
120 case Core::HID::NpadStyleIndex::Handheld: 120 case Core::HID::NpadStyleIndex::Handheld:
@@ -345,7 +345,7 @@ SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
345 const Core::HID::SixAxisSensorHandle& sixaxis_handle) { 345 const Core::HID::SixAxisSensorHandle& sixaxis_handle) {
346 auto& controller = GetControllerFromHandle(sixaxis_handle); 346 auto& controller = GetControllerFromHandle(sixaxis_handle);
347 switch (sixaxis_handle.npad_type) { 347 switch (sixaxis_handle.npad_type) {
348 case Core::HID::NpadStyleIndex::ProController: 348 case Core::HID::NpadStyleIndex::Fullkey:
349 case Core::HID::NpadStyleIndex::Pokeball: 349 case Core::HID::NpadStyleIndex::Pokeball:
350 return controller.sixaxis_fullkey; 350 return controller.sixaxis_fullkey;
351 case Core::HID::NpadStyleIndex::Handheld: 351 case Core::HID::NpadStyleIndex::Handheld:
@@ -368,7 +368,7 @@ const SixAxis::SixaxisParameters& SixAxis::GetSixaxisState(
368 const Core::HID::SixAxisSensorHandle& sixaxis_handle) const { 368 const Core::HID::SixAxisSensorHandle& sixaxis_handle) const {
369 const auto& controller = GetControllerFromHandle(sixaxis_handle); 369 const auto& controller = GetControllerFromHandle(sixaxis_handle);
370 switch (sixaxis_handle.npad_type) { 370 switch (sixaxis_handle.npad_type) {
371 case Core::HID::NpadStyleIndex::ProController: 371 case Core::HID::NpadStyleIndex::Fullkey:
372 case Core::HID::NpadStyleIndex::Pokeball: 372 case Core::HID::NpadStyleIndex::Pokeball:
373 return controller.sixaxis_fullkey; 373 return controller.sixaxis_fullkey;
374 case Core::HID::NpadStyleIndex::Handheld: 374 case Core::HID::NpadStyleIndex::Handheld:
diff --git a/src/hid_core/resources/vibration/gc_vibration_device.cpp b/src/hid_core/resources/vibration/gc_vibration_device.cpp
new file mode 100644
index 000000000..f01f81b9a
--- /dev/null
+++ b/src/hid_core/resources/vibration/gc_vibration_device.cpp
@@ -0,0 +1,106 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/npad/npad_types.h"
6#include "hid_core/resources/npad/npad_vibration.h"
7#include "hid_core/resources/vibration/gc_vibration_device.h"
8
9namespace Service::HID {
10
11NpadGcVibrationDevice::NpadGcVibrationDevice() {}
12
13Result NpadGcVibrationDevice::IncrementRefCounter() {
14 if (ref_counter == 0 && is_mounted) {
15 f32 volume = 1.0f;
16 const auto result = vibration_handler->GetVibrationVolume(volume);
17 if (result.IsSuccess()) {
18 // TODO: SendVibrationGcErmCommand
19 }
20 }
21 ref_counter++;
22 return ResultSuccess;
23}
24
25Result NpadGcVibrationDevice::DecrementRefCounter() {
26 if (ref_counter == 1 && !is_mounted) {
27 f32 volume = 1.0f;
28 const auto result = vibration_handler->GetVibrationVolume(volume);
29 if (result.IsSuccess()) {
30 // TODO: SendVibrationGcErmCommand
31 }
32 }
33
34 if (ref_counter > 0) {
35 ref_counter--;
36 }
37
38 return ResultSuccess;
39}
40
41Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command) {
42 if (!is_mounted) {
43 return ResultSuccess;
44 }
45 f32 volume = 1.0f;
46 const auto result = vibration_handler->GetVibrationVolume(volume);
47 if (result.IsError()) {
48 return result;
49 }
50 if (volume == 0.0) {
51 command = Core::HID::VibrationGcErmCommand::Stop;
52 } else {
53 if (command > Core::HID::VibrationGcErmCommand::StopHard) {
54 // Abort
55 return ResultSuccess;
56 }
57 }
58 // TODO: SendVibrationGcErmCommand
59 return ResultSuccess;
60}
61
62Result NpadGcVibrationDevice::GetActualVibrationGcErmCommand(
63 Core::HID::VibrationGcErmCommand& out_command) {
64 if (!is_mounted) {
65 out_command = Core::HID::VibrationGcErmCommand::Stop;
66 return ResultSuccess;
67 }
68
69 f32 volume = 1.0f;
70 const auto result = vibration_handler->GetVibrationVolume(volume);
71 if (result.IsError()) {
72 return result;
73 }
74 if (volume == 0.0f) {
75 out_command = Core::HID::VibrationGcErmCommand::Stop;
76 return ResultSuccess;
77 }
78
79 // TODO: GetActualVibrationGcErmCommand
80 return ResultSuccess;
81}
82
83Result NpadGcVibrationDevice::SendVibrationNotificationPattern(
84 Core::HID::VibrationGcErmCommand command) {
85 if (!is_mounted) {
86 return ResultSuccess;
87 }
88
89 f32 volume = 1.0f;
90 const auto result = vibration_handler->GetVibrationVolume(volume);
91 if (result.IsError()) {
92 return result;
93 }
94 if (volume <= 0.0f) {
95 command = Core::HID::VibrationGcErmCommand::Stop;
96 }
97 if (command > Core::HID::VibrationGcErmCommand::StopHard) {
98 // Abort
99 return ResultSuccess;
100 }
101
102 // TODO: SendVibrationNotificationPattern
103 return ResultSuccess;
104}
105
106} // namespace Service::HID
diff --git a/src/hid_core/resources/vibration/gc_vibration_device.h b/src/hid_core/resources/vibration/gc_vibration_device.h
new file mode 100644
index 000000000..87abca57d
--- /dev/null
+++ b/src/hid_core/resources/vibration/gc_vibration_device.h
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <mutex>
8
9#include "common/common_types.h"
10#include "core/hle/result.h"
11#include "hid_core/hid_types.h"
12#include "hid_core/resources/npad/npad_types.h"
13#include "hid_core/resources/vibration/vibration_base.h"
14
15namespace Service::HID {
16class NpadVibration;
17
18/// Handles Npad request from HID interfaces
19class NpadGcVibrationDevice final : public NpadVibrationBase {
20public:
21 explicit NpadGcVibrationDevice();
22
23 Result IncrementRefCounter() override;
24 Result DecrementRefCounter() override;
25
26 Result SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command);
27
28 Result GetActualVibrationGcErmCommand(Core::HID::VibrationGcErmCommand& out_command);
29 Result SendVibrationNotificationPattern(Core::HID::VibrationGcErmCommand command);
30};
31} // namespace Service::HID
diff --git a/src/hid_core/resources/vibration/n64_vibration_device.cpp b/src/hid_core/resources/vibration/n64_vibration_device.cpp
new file mode 100644
index 000000000..639f87abf
--- /dev/null
+++ b/src/hid_core/resources/vibration/n64_vibration_device.cpp
@@ -0,0 +1,80 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/npad/npad_types.h"
6#include "hid_core/resources/npad/npad_vibration.h"
7#include "hid_core/resources/vibration/n64_vibration_device.h"
8
9namespace Service::HID {
10
11NpadN64VibrationDevice::NpadN64VibrationDevice() {}
12
13Result NpadN64VibrationDevice::IncrementRefCounter() {
14 if (ref_counter == 0 && is_mounted) {
15 f32 volume = 1.0f;
16 const auto result = vibration_handler->GetVibrationVolume(volume);
17 if (result.IsSuccess()) {
18 // TODO: SendVibrationInBool
19 }
20 }
21
22 ref_counter++;
23 return ResultSuccess;
24}
25
26Result NpadN64VibrationDevice::DecrementRefCounter() {
27 if (ref_counter == 1) {
28 if (!is_mounted) {
29 ref_counter = 0;
30 if (is_mounted != false) {
31 // TODO: SendVibrationInBool
32 }
33 return ResultSuccess;
34 }
35 f32 volume = 1.0f;
36 const auto result = vibration_handler->GetVibrationVolume(volume);
37 if (result.IsSuccess()) {
38 // TODO
39 }
40 }
41
42 if (ref_counter > 0) {
43 ref_counter--;
44 }
45
46 return ResultSuccess;
47}
48
49Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) {
50 if (ref_counter < 1) {
51 return ResultVibrationNotInitialized;
52 }
53 if (is_mounted) {
54 f32 volume = 1.0f;
55 const auto result = vibration_handler->GetVibrationVolume(volume);
56 if (result.IsError()) {
57 return result;
58 }
59 // TODO: SendVibrationInBool
60 }
61 return ResultSuccess;
62}
63
64Result NpadN64VibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u32 pattern) {
65 if (!is_mounted) {
66 return ResultSuccess;
67 }
68 f32 volume = 1.0f;
69 const auto result = vibration_handler->GetVibrationVolume(volume);
70 if (result.IsError()) {
71 return result;
72 }
73 if (volume <= 0.0) {
74 pattern = 0;
75 }
76 // TODO: SendVibrationNotificationPattern
77 return ResultSuccess;
78}
79
80} // namespace Service::HID
diff --git a/src/hid_core/resources/vibration/n64_vibration_device.h b/src/hid_core/resources/vibration/n64_vibration_device.h
new file mode 100644
index 000000000..54e6efc1a
--- /dev/null
+++ b/src/hid_core/resources/vibration/n64_vibration_device.h
@@ -0,0 +1,29 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <mutex>
8
9#include "common/common_types.h"
10#include "core/hle/result.h"
11#include "hid_core/hid_types.h"
12#include "hid_core/resources/npad/npad_types.h"
13#include "hid_core/resources/vibration/vibration_base.h"
14
15namespace Service::HID {
16class NpadVibration;
17
18/// Handles Npad request from HID interfaces
19class NpadN64VibrationDevice final : public NpadVibrationBase {
20public:
21 explicit NpadN64VibrationDevice();
22
23 Result IncrementRefCounter() override;
24 Result DecrementRefCounter() override;
25
26 Result SendValueInBool(bool is_vibrating);
27 Result SendVibrationNotificationPattern(u32 pattern);
28};
29} // namespace Service::HID
diff --git a/src/hid_core/resources/vibration/vibration_base.cpp b/src/hid_core/resources/vibration/vibration_base.cpp
new file mode 100644
index 000000000..350f349c2
--- /dev/null
+++ b/src/hid_core/resources/vibration/vibration_base.cpp
@@ -0,0 +1,30 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/npad/npad_types.h"
6#include "hid_core/resources/npad/npad_vibration.h"
7#include "hid_core/resources/vibration/vibration_base.h"
8
9namespace Service::HID {
10
11NpadVibrationBase::NpadVibrationBase() {}
12
13Result NpadVibrationBase::IncrementRefCounter() {
14 ref_counter++;
15 return ResultSuccess;
16}
17
18Result NpadVibrationBase::DecrementRefCounter() {
19 if (ref_counter > 0) {
20 ref_counter--;
21 }
22
23 return ResultSuccess;
24}
25
26bool NpadVibrationBase::IsVibrationMounted() const {
27 return is_mounted;
28}
29
30} // namespace Service::HID
diff --git a/src/hid_core/resources/vibration/vibration_base.h b/src/hid_core/resources/vibration/vibration_base.h
new file mode 100644
index 000000000..c6c5fc4d9
--- /dev/null
+++ b/src/hid_core/resources/vibration/vibration_base.h
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hle/result.h"
8
9namespace Service::HID {
10class NpadVibration;
11
12/// Handles Npad request from HID interfaces
13class NpadVibrationBase {
14public:
15 explicit NpadVibrationBase();
16
17 virtual Result IncrementRefCounter();
18 virtual Result DecrementRefCounter();
19
20 bool IsVibrationMounted() const;
21
22protected:
23 u64 xcd_handle{};
24 s32 ref_counter{};
25 bool is_mounted{};
26 NpadVibration* vibration_handler{nullptr};
27};
28} // namespace Service::HID
diff --git a/src/hid_core/resources/vibration/vibration_device.cpp b/src/hid_core/resources/vibration/vibration_device.cpp
new file mode 100644
index 000000000..888c3a7ed
--- /dev/null
+++ b/src/hid_core/resources/vibration/vibration_device.cpp
@@ -0,0 +1,84 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "hid_core/hid_result.h"
5#include "hid_core/resources/npad/npad_types.h"
6#include "hid_core/resources/npad/npad_vibration.h"
7#include "hid_core/resources/vibration/vibration_device.h"
8
9namespace Service::HID {
10
11NpadVibrationDevice::NpadVibrationDevice() {}
12
13Result NpadVibrationDevice::IncrementRefCounter() {
14 ref_counter++;
15 return ResultSuccess;
16}
17
18Result NpadVibrationDevice::DecrementRefCounter() {
19 if (ref_counter > 0) {
20 ref_counter--;
21 }
22
23 return ResultSuccess;
24}
25
26Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& value) {
27 if (ref_counter == 0) {
28 return ResultVibrationNotInitialized;
29 }
30 if (!is_mounted) {
31 return ResultSuccess;
32 }
33
34 f32 volume = 1.0f;
35 const auto result = vibration_handler->GetVibrationVolume(volume);
36 if (result.IsError()) {
37 return result;
38 }
39 if (volume <= 0.0f) {
40 // TODO: SendVibrationValue
41 return ResultSuccess;
42 }
43
44 Core::HID::VibrationValue vibration_value = value;
45 vibration_value.high_amplitude *= volume;
46 vibration_value.low_amplitude *= volume;
47
48 // TODO: SendVibrationValue
49 return ResultSuccess;
50}
51
52Result NpadVibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u32 pattern) {
53 if (!is_mounted) {
54 return ResultSuccess;
55 }
56
57 f32 volume = 1.0f;
58 const auto result = vibration_handler->GetVibrationVolume(volume);
59 if (result.IsError()) {
60 return result;
61 }
62 if (volume <= 0.0) {
63 pattern = 0;
64 }
65
66 // return xcd_handle->SendVibrationNotificationPattern(pattern);
67 return ResultSuccess;
68}
69
70Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) {
71 if (ref_counter < 1) {
72 return ResultVibrationNotInitialized;
73 }
74
75 out_value = Core::HID::DEFAULT_VIBRATION_VALUE;
76 if (!is_mounted) {
77 return ResultSuccess;
78 }
79
80 // TODO: SendVibrationValue
81 return ResultSuccess;
82}
83
84} // namespace Service::HID
diff --git a/src/hid_core/resources/vibration/vibration_device.h b/src/hid_core/resources/vibration/vibration_device.h
new file mode 100644
index 000000000..3574ad60b
--- /dev/null
+++ b/src/hid_core/resources/vibration/vibration_device.h
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include <mutex>
8
9#include "common/common_types.h"
10#include "core/hle/result.h"
11#include "hid_core/hid_types.h"
12#include "hid_core/resources/npad/npad_types.h"
13#include "hid_core/resources/vibration/vibration_base.h"
14
15namespace Service::HID {
16class NpadVibration;
17
18/// Handles Npad request from HID interfaces
19class NpadVibrationDevice final : public NpadVibrationBase {
20public:
21 explicit NpadVibrationDevice();
22
23 Result IncrementRefCounter();
24 Result DecrementRefCounter();
25
26 Result SendVibrationValue(const Core::HID::VibrationValue& value);
27 Result SendVibrationNotificationPattern(u32 pattern);
28
29 Result GetActualVibrationValue(Core::HID::VibrationValue& out_value);
30
31private:
32 u32 device_index{};
33};
34
35} // namespace Service::HID
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index 8b340ee6c..48ce860ad 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -41,7 +41,7 @@ void UpdateController(Core::HID::EmulatedController* controller,
41bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type, 41bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type,
42 Core::Frontend::ControllerParameters parameters) { 42 Core::Frontend::ControllerParameters parameters) {
43 switch (controller_type) { 43 switch (controller_type) {
44 case Core::HID::NpadStyleIndex::ProController: 44 case Core::HID::NpadStyleIndex::Fullkey:
45 return parameters.allow_pro_controller; 45 return parameters.allow_pro_controller;
46 case Core::HID::NpadStyleIndex::JoyconDual: 46 case Core::HID::NpadStyleIndex::JoyconDual:
47 return parameters.allow_dual_joycons; 47 return parameters.allow_dual_joycons;
@@ -462,7 +462,7 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index
462 }; 462 };
463 463
464 if (npad_style_set.fullkey == 1) { 464 if (npad_style_set.fullkey == 1) {
465 add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller")); 465 add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller"));
466 } 466 }
467 467
468 if (npad_style_set.joycon_dual == 1) { 468 if (npad_style_set.joycon_dual == 1) {
@@ -519,7 +519,7 @@ Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex
519 [index](const auto& pair) { return pair.first == index; }); 519 [index](const auto& pair) { return pair.first == index; });
520 520
521 if (it == pairs.end()) { 521 if (it == pairs.end()) {
522 return Core::HID::NpadStyleIndex::ProController; 522 return Core::HID::NpadStyleIndex::Fullkey;
523 } 523 }
524 524
525 return it->second; 525 return it->second;
@@ -549,7 +549,7 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
549 const QString stylesheet = [this, player_index] { 549 const QString stylesheet = [this, player_index] {
550 switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), 550 switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
551 player_index)) { 551 player_index)) {
552 case Core::HID::NpadStyleIndex::ProController: 552 case Core::HID::NpadStyleIndex::Fullkey:
553 case Core::HID::NpadStyleIndex::GameCube: 553 case Core::HID::NpadStyleIndex::GameCube:
554 return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); 554 return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
555 case Core::HID::NpadStyleIndex::JoyconDual: 555 case Core::HID::NpadStyleIndex::JoyconDual:
diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp
index bbe17c35e..ac81ace9e 100644
--- a/src/yuzu/applets/qt_software_keyboard.cpp
+++ b/src/yuzu/applets/qt_software_keyboard.cpp
@@ -832,7 +832,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
832 }(); 832 }();
833 833
834 switch (controller_type) { 834 switch (controller_type) {
835 case Core::HID::NpadStyleIndex::ProController: 835 case Core::HID::NpadStyleIndex::Fullkey:
836 case Core::HID::NpadStyleIndex::GameCube: 836 case Core::HID::NpadStyleIndex::GameCube:
837 ui->icon_controller->setStyleSheet( 837 ui->icon_controller->setStyleSheet(
838 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); 838 QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index f3552191a..5dac9f1e7 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -1094,7 +1094,7 @@ void ConfigureInputPlayer::SetConnectableControllers() {
1094 }; 1094 };
1095 1095
1096 if (npad_style_set.fullkey == 1) { 1096 if (npad_style_set.fullkey == 1) {
1097 add_item(Core::HID::NpadStyleIndex::ProController, tr("Pro Controller")); 1097 add_item(Core::HID::NpadStyleIndex::Fullkey, tr("Pro Controller"));
1098 } 1098 }
1099 1099
1100 if (npad_style_set.joycon_dual == 1) { 1100 if (npad_style_set.joycon_dual == 1) {
@@ -1149,7 +1149,7 @@ Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int i
1149 [index](const auto& pair) { return pair.first == index; }); 1149 [index](const auto& pair) { return pair.first == index; });
1150 1150
1151 if (it == index_controller_type_pairs.end()) { 1151 if (it == index_controller_type_pairs.end()) {
1152 return Core::HID::NpadStyleIndex::ProController; 1152 return Core::HID::NpadStyleIndex::Fullkey;
1153 } 1153 }
1154 1154
1155 return it->second; 1155 return it->second;
@@ -1178,7 +1178,7 @@ void ConfigureInputPlayer::UpdateInputDevices() {
1178void ConfigureInputPlayer::UpdateControllerAvailableButtons() { 1178void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1179 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); 1179 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
1180 if (debug) { 1180 if (debug) {
1181 layout = Core::HID::NpadStyleIndex::ProController; 1181 layout = Core::HID::NpadStyleIndex::Fullkey;
1182 } 1182 }
1183 1183
1184 // List of all the widgets that will be hidden by any of the following layouts that need 1184 // List of all the widgets that will be hidden by any of the following layouts that need
@@ -1206,7 +1206,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1206 1206
1207 std::vector<QWidget*> layout_hidden; 1207 std::vector<QWidget*> layout_hidden;
1208 switch (layout) { 1208 switch (layout) {
1209 case Core::HID::NpadStyleIndex::ProController: 1209 case Core::HID::NpadStyleIndex::Fullkey:
1210 case Core::HID::NpadStyleIndex::Handheld: 1210 case Core::HID::NpadStyleIndex::Handheld:
1211 layout_hidden = { 1211 layout_hidden = {
1212 ui->buttonShoulderButtonsSLSRLeft, 1212 ui->buttonShoulderButtonsSLSRLeft,
@@ -1254,7 +1254,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1254void ConfigureInputPlayer::UpdateControllerEnabledButtons() { 1254void ConfigureInputPlayer::UpdateControllerEnabledButtons() {
1255 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); 1255 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
1256 if (debug) { 1256 if (debug) {
1257 layout = Core::HID::NpadStyleIndex::ProController; 1257 layout = Core::HID::NpadStyleIndex::Fullkey;
1258 } 1258 }
1259 1259
1260 // List of all the widgets that will be disabled by any of the following layouts that need 1260 // List of all the widgets that will be disabled by any of the following layouts that need
@@ -1271,7 +1271,7 @@ void ConfigureInputPlayer::UpdateControllerEnabledButtons() {
1271 1271
1272 std::vector<QWidget*> layout_disable; 1272 std::vector<QWidget*> layout_disable;
1273 switch (layout) { 1273 switch (layout) {
1274 case Core::HID::NpadStyleIndex::ProController: 1274 case Core::HID::NpadStyleIndex::Fullkey:
1275 case Core::HID::NpadStyleIndex::JoyconDual: 1275 case Core::HID::NpadStyleIndex::JoyconDual:
1276 case Core::HID::NpadStyleIndex::Handheld: 1276 case Core::HID::NpadStyleIndex::Handheld:
1277 case Core::HID::NpadStyleIndex::JoyconLeft: 1277 case Core::HID::NpadStyleIndex::JoyconLeft:
@@ -1304,7 +1304,7 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
1304 1304
1305 // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller. 1305 // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller.
1306 switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { 1306 switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) {
1307 case Core::HID::NpadStyleIndex::ProController: 1307 case Core::HID::NpadStyleIndex::Fullkey:
1308 case Core::HID::NpadStyleIndex::JoyconLeft: 1308 case Core::HID::NpadStyleIndex::JoyconLeft:
1309 case Core::HID::NpadStyleIndex::Handheld: 1309 case Core::HID::NpadStyleIndex::Handheld:
1310 // Show "Motion 1" and hide "Motion 2". 1310 // Show "Motion 1" and hide "Motion 2".
@@ -1333,11 +1333,11 @@ void ConfigureInputPlayer::UpdateMotionButtons() {
1333void ConfigureInputPlayer::UpdateControllerButtonNames() { 1333void ConfigureInputPlayer::UpdateControllerButtonNames() {
1334 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); 1334 auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex());
1335 if (debug) { 1335 if (debug) {
1336 layout = Core::HID::NpadStyleIndex::ProController; 1336 layout = Core::HID::NpadStyleIndex::Fullkey;
1337 } 1337 }
1338 1338
1339 switch (layout) { 1339 switch (layout) {
1340 case Core::HID::NpadStyleIndex::ProController: 1340 case Core::HID::NpadStyleIndex::Fullkey:
1341 case Core::HID::NpadStyleIndex::JoyconDual: 1341 case Core::HID::NpadStyleIndex::JoyconDual:
1342 case Core::HID::NpadStyleIndex::Handheld: 1342 case Core::HID::NpadStyleIndex::Handheld:
1343 case Core::HID::NpadStyleIndex::JoyconLeft: 1343 case Core::HID::NpadStyleIndex::JoyconLeft:
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index 19fdca7d3..8f91f5e92 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -244,7 +244,7 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) {
244 case Core::HID::NpadStyleIndex::GameCube: 244 case Core::HID::NpadStyleIndex::GameCube:
245 DrawGCController(p, center); 245 DrawGCController(p, center);
246 break; 246 break;
247 case Core::HID::NpadStyleIndex::ProController: 247 case Core::HID::NpadStyleIndex::Fullkey:
248 default: 248 default:
249 DrawProController(p, center); 249 DrawProController(p, center);
250 break; 250 break;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 4f4c75f5c..fd5342537 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -3988,7 +3988,7 @@ void GMainWindow::OnToggleDockedMode() {
3988 tr("Handheld controller can't be used on docked mode. Pro " 3988 tr("Handheld controller can't be used on docked mode. Pro "
3989 "controller will be selected.")); 3989 "controller will be selected."));
3990 handheld->Disconnect(); 3990 handheld->Disconnect();
3991 player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); 3991 player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Fullkey);
3992 player_1->Connect(); 3992 player_1->Connect();
3993 controller_dialog->refreshConfiguration(); 3993 controller_dialog->refreshConfiguration();
3994 } 3994 }
diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp
index 2690b075d..0dbfca243 100644
--- a/src/yuzu/util/controller_navigation.cpp
+++ b/src/yuzu/util/controller_navigation.cpp
@@ -66,7 +66,7 @@ void ControllerNavigation::ControllerUpdateButton() {
66 } 66 }
67 67
68 switch (controller_type) { 68 switch (controller_type) {
69 case Core::HID::NpadStyleIndex::ProController: 69 case Core::HID::NpadStyleIndex::Fullkey:
70 case Core::HID::NpadStyleIndex::JoyconDual: 70 case Core::HID::NpadStyleIndex::JoyconDual:
71 case Core::HID::NpadStyleIndex::Handheld: 71 case Core::HID::NpadStyleIndex::Handheld:
72 case Core::HID::NpadStyleIndex::GameCube: 72 case Core::HID::NpadStyleIndex::GameCube:
@@ -116,7 +116,7 @@ void ControllerNavigation::ControllerUpdateStick() {
116 } 116 }
117 117
118 switch (controller_type) { 118 switch (controller_type) {
119 case Core::HID::NpadStyleIndex::ProController: 119 case Core::HID::NpadStyleIndex::Fullkey:
120 case Core::HID::NpadStyleIndex::JoyconDual: 120 case Core::HID::NpadStyleIndex::JoyconDual:
121 case Core::HID::NpadStyleIndex::Handheld: 121 case Core::HID::NpadStyleIndex::Handheld:
122 case Core::HID::NpadStyleIndex::GameCube: 122 case Core::HID::NpadStyleIndex::GameCube: