summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt52
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt7
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt30
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt61
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt7
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt7
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt7
-rw-r--r--src/android/app/src/main/jni/uisettings.h2
-rw-r--r--src/android/app/src/main/res/drawable/ic_audio.xml9
-rw-r--r--src/android/app/src/main/res/drawable/ic_code.xml9
-rw-r--r--src/android/app/src/main/res/drawable/ic_graphics.xml9
-rw-r--r--src/android/app/src/main/res/drawable/ic_system_settings.xml9
-rw-r--r--src/android/app/src/main/res/layout-w600dp/fragment_about.xml233
-rw-r--r--src/android/app/src/main/res/layout/card_home_option.xml4
-rw-r--r--src/android/app/src/main/res/layout/fragment_about.xml10
-rw-r--r--src/android/app/src/main/res/layout/fragment_emulation.xml5
-rw-r--r--src/android/app/src/main/res/layout/fragment_home_settings.xml9
-rw-r--r--src/android/app/src/main/res/layout/list_item_setting.xml72
-rw-r--r--src/android/app/src/main/res/layout/list_item_setting_switch.xml8
-rw-r--r--src/android/app/src/main/res/layout/list_item_settings_header.xml3
-rw-r--r--src/android/app/src/main/res/values/arrays.xml2
-rw-r--r--src/android/app/src/main/res/values/strings.xml5
-rw-r--r--src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp2
-rw-r--r--src/audio_core/opus/decoder.cpp2
-rw-r--r--src/audio_core/sink/cubeb_sink.cpp2
-rw-r--r--src/audio_core/sink/sdl2_sink.cpp2
-rw-r--r--src/audio_core/sink/sink_stream.cpp12
-rw-r--r--src/audio_core/sink/sink_stream.h6
-rw-r--r--src/common/settings.cpp2
-rw-r--r--src/common/settings.h2
-rw-r--r--src/common/settings_common.h1
-rw-r--r--src/common/settings_input.cpp9
-rw-r--r--src/common/settings_input.h7
-rw-r--r--src/core/CMakeLists.txt11
-rw-r--r--src/core/arm/arm_interface.cpp16
-rw-r--r--src/core/core_timing.cpp2
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/hid/emulated_console.h8
-rw-r--r--src/core/hid/emulated_controller.cpp28
-rw-r--r--src/core/hid/hid_types.h8
-rw-r--r--src/core/hid/input_interpreter.cpp7
-rw-r--r--src/core/hle/kernel/k_page_table_base.cpp4
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.cpp9
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h4
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp6
-rw-r--r--src/core/hle/service/hid/controllers/npad.h7
-rw-r--r--src/core/hle/service/hid/controllers/palma.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp2859
-rw-r--r--src/core/hle/service/hid/hid.h212
-rw-r--r--src/core/hle/service/hid/hid_debug_server.cpp159
-rw-r--r--src/core/hle/service/hid/hid_debug_server.h26
-rw-r--r--src/core/hle/service/hid/hid_firmware_settings.cpp99
-rw-r--r--src/core/hle/service/hid/hid_firmware_settings.h54
-rw-r--r--src/core/hle/service/hid/hid_server.cpp2440
-rw-r--r--src/core/hle/service/hid/hid_server.h149
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp304
-rw-r--r--src/core/hle/service/hid/hid_system_server.h40
-rw-r--r--src/core/hle/service/hid/irs.h5
-rw-r--r--src/core/hle/service/hid/resource_manager.cpp184
-rw-r--r--src/core/hle/service/hid/resource_manager.h104
-rw-r--r--src/core/hle/service/nvnflinger/buffer_item.h2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp27
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_consumer.h9
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_core.cpp12
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_core.h3
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.cpp19
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.h3
-rw-r--r--src/core/hle/service/nvnflinger/buffer_slot.h2
-rw-r--r--src/core/hle/service/nvnflinger/consumer_base.cpp20
-rw-r--r--src/core/hle/service/nvnflinger/consumer_base.h2
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp2
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp22
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h2
-rw-r--r--src/core/hle/service/nvnflinger/status.h2
-rw-r--r--src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp34
-rw-r--r--src/core/hle/service/nvnflinger/ui/graphic_buffer.h25
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp2
-rw-r--r--src/core/memory.cpp25
-rw-r--r--src/core/memory/cheat_engine.cpp7
-rw-r--r--src/input_common/drivers/gc_adapter.cpp8
-rw-r--r--src/input_common/drivers/joycon.cpp8
-rw-r--r--src/input_common/drivers/sdl_driver.cpp20
-rw-r--r--src/input_common/drivers/sdl_driver.h2
-rw-r--r--src/input_common/drivers/udp_client.cpp8
-rw-r--r--src/shader_recompiler/CMakeLists.txt1
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm_image.cpp6
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_image.cpp6
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_image.cpp56
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h2
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.cpp4
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h2
-rw-r--r--src/shader_recompiler/frontend/ir/modifiers.h2
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp29
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate_program.cpp1
-rw-r--r--src/shader_recompiler/ir_opt/constant_propagation_pass.cpp10
-rw-r--r--src/shader_recompiler/ir_opt/passes.h1
-rw-r--r--src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp79
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h5
-rw-r--r--src/video_core/engines/fermi_2d.cpp4
-rw-r--r--src/video_core/engines/maxwell_3d.cpp2
-rw-r--r--src/video_core/fence_manager.h5
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.cpp6
-rw-r--r--src/video_core/renderer_opengl/gl_graphics_pipeline.h1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp2
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp14
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h4
-rw-r--r--src/yuzu/applets/qt_controller.cpp1
-rw-r--r--src/yuzu/configuration/config.cpp3
-rw-r--r--src/yuzu/configuration/configure_audio.cpp10
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp36
-rw-r--r--src/yuzu/configuration/configure_input_player.ui389
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp45
-rw-r--r--src/yuzu/game_list.cpp6
-rw-r--r--src/yuzu/main.cpp437
-rw-r--r--src/yuzu/main.h21
-rw-r--r--src/yuzu/uisettings.h10
-rw-r--r--src/yuzu/util/util.cpp12
-rw-r--r--src/yuzu/util/util.h3
125 files changed, 5102 insertions, 3791 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
index 054e4b755..f41d7bdbf 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
@@ -373,8 +373,10 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
373 val pictureInPictureParamsBuilder = PictureInPictureParams.Builder() 373 val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
374 .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder() 374 .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
375 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 375 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
376 val isEmulationActive = emulationViewModel.emulationStarted.value &&
377 !emulationViewModel.isEmulationStopping.value
376 pictureInPictureParamsBuilder.setAutoEnterEnabled( 378 pictureInPictureParamsBuilder.setAutoEnterEnabled(
377 BooleanSetting.PICTURE_IN_PICTURE.boolean 379 BooleanSetting.PICTURE_IN_PICTURE.boolean && isEmulationActive
378 ) 380 )
379 } 381 }
380 setPictureInPictureParams(pictureInPictureParamsBuilder.build()) 382 setPictureInPictureParams(pictureInPictureParamsBuilder.build())
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 0c82cdba8..2ef638559 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
@@ -22,12 +22,16 @@ import androidx.core.graphics.drawable.toBitmap
22import androidx.core.graphics.drawable.toDrawable 22import androidx.core.graphics.drawable.toDrawable
23import androidx.documentfile.provider.DocumentFile 23import androidx.documentfile.provider.DocumentFile
24import androidx.lifecycle.ViewModelProvider 24import androidx.lifecycle.ViewModelProvider
25import androidx.lifecycle.lifecycleScope
25import androidx.navigation.findNavController 26import androidx.navigation.findNavController
26import androidx.preference.PreferenceManager 27import androidx.preference.PreferenceManager
27import androidx.recyclerview.widget.AsyncDifferConfig 28import androidx.recyclerview.widget.AsyncDifferConfig
28import androidx.recyclerview.widget.DiffUtil 29import androidx.recyclerview.widget.DiffUtil
29import androidx.recyclerview.widget.ListAdapter 30import androidx.recyclerview.widget.ListAdapter
30import androidx.recyclerview.widget.RecyclerView 31import androidx.recyclerview.widget.RecyclerView
32import kotlinx.coroutines.Dispatchers
33import kotlinx.coroutines.launch
34import kotlinx.coroutines.withContext
31import org.yuzu.yuzu_emu.HomeNavigationDirections 35import org.yuzu.yuzu_emu.HomeNavigationDirections
32import org.yuzu.yuzu_emu.R 36import org.yuzu.yuzu_emu.R
33import org.yuzu.yuzu_emu.YuzuApplication 37import org.yuzu.yuzu_emu.YuzuApplication
@@ -92,28 +96,34 @@ class GameAdapter(private val activity: AppCompatActivity) :
92 data = Uri.parse(holder.game.path) 96 data = Uri.parse(holder.game.path)
93 } 97 }
94 98
95 val layerDrawable = ResourcesCompat.getDrawable( 99 activity.lifecycleScope.launch {
96 YuzuApplication.appContext.resources, 100 withContext(Dispatchers.IO) {
97 R.drawable.shortcut, 101 val layerDrawable = ResourcesCompat.getDrawable(
98 null 102 YuzuApplication.appContext.resources,
99 ) as LayerDrawable 103 R.drawable.shortcut,
100 layerDrawable.setDrawableByLayerId( 104 null
101 R.id.shortcut_foreground, 105 ) as LayerDrawable
102 GameIconUtils.getGameIcon(holder.game).toDrawable(YuzuApplication.appContext.resources) 106 layerDrawable.setDrawableByLayerId(
103 ) 107 R.id.shortcut_foreground,
104 val inset = YuzuApplication.appContext.resources 108 GameIconUtils.getGameIcon(activity, holder.game)
105 .getDimensionPixelSize(R.dimen.icon_inset) 109 .toDrawable(YuzuApplication.appContext.resources)
106 layerDrawable.setLayerInset(1, inset, inset, inset, inset)
107 val shortcut = ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
108 .setShortLabel(holder.game.title)
109 .setIcon(
110 IconCompat.createWithAdaptiveBitmap(
111 layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
112 ) 110 )
113 ) 111 val inset = YuzuApplication.appContext.resources
114 .setIntent(openIntent) 112 .getDimensionPixelSize(R.dimen.icon_inset)
115 .build() 113 layerDrawable.setLayerInset(1, inset, inset, inset, inset)
116 ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut) 114 val shortcut =
115 ShortcutInfoCompat.Builder(YuzuApplication.appContext, holder.game.path)
116 .setShortLabel(holder.game.title)
117 .setIcon(
118 IconCompat.createWithAdaptiveBitmap(
119 layerDrawable.toBitmap(config = Bitmap.Config.ARGB_8888)
120 )
121 )
122 .setIntent(openIntent)
123 .build()
124 ShortcutManagerCompat.pushDynamicShortcut(YuzuApplication.appContext, shortcut)
125 }
126 }
117 127
118 val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game) 128 val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game)
119 view.findNavController().navigate(action) 129 view.findNavController().navigate(action)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
index 08e2a973d..2bf0e1b0d 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
@@ -82,7 +82,6 @@ object Settings {
82 82
83 enum class MenuTag(val titleId: Int) { 83 enum class MenuTag(val titleId: Int) {
84 SECTION_ROOT(R.string.advanced_settings), 84 SECTION_ROOT(R.string.advanced_settings),
85 SECTION_GENERAL(R.string.preferences_general),
86 SECTION_SYSTEM(R.string.preferences_system), 85 SECTION_SYSTEM(R.string.preferences_system),
87 SECTION_RENDERER(R.string.preferences_graphics), 86 SECTION_RENDERER(R.string.preferences_graphics),
88 SECTION_AUDIO(R.string.preferences_audio), 87 SECTION_AUDIO(R.string.preferences_audio),
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt
index 522cc49df..425160024 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/RunnableSetting.kt
@@ -3,10 +3,13 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.model.view 4package org.yuzu.yuzu_emu.features.settings.model.view
5 5
6import androidx.annotation.DrawableRes
7
6class RunnableSetting( 8class RunnableSetting(
7 titleId: Int, 9 titleId: Int,
8 descriptionId: Int, 10 descriptionId: Int,
9 val isRuntimeRunnable: Boolean, 11 val isRuntimeRunnable: Boolean,
12 @DrawableRes val iconId: Int = 0,
10 val runnable: () -> Unit 13 val runnable: () -> Unit
11) : SettingsItem(emptySetting, titleId, descriptionId) { 14) : SettingsItem(emptySetting, titleId, descriptionId) {
12 override val type = TYPE_RUNNABLE 15 override val type = TYPE_RUNNABLE
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt
index b343e527e..94953b18a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt
@@ -3,11 +3,14 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.model.view 4package org.yuzu.yuzu_emu.features.settings.model.view
5 5
6import androidx.annotation.DrawableRes
7import androidx.annotation.StringRes
6import org.yuzu.yuzu_emu.features.settings.model.Settings 8import org.yuzu.yuzu_emu.features.settings.model.Settings
7 9
8class SubmenuSetting( 10class SubmenuSetting(
9 titleId: Int, 11 @StringRes titleId: Int,
10 descriptionId: Int, 12 @StringRes descriptionId: Int,
13 @DrawableRes val iconId: Int,
11 val menuKey: Settings.MenuTag 14 val menuKey: Settings.MenuTag
12) : SettingsItem(emptySetting, titleId, descriptionId) { 15) : SettingsItem(emptySetting, titleId, descriptionId) {
13 override val type = TYPE_SUBMENU 16 override val type = TYPE_SUBMENU
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
index 70d8ec14b..769baf744 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
@@ -20,7 +20,6 @@ import androidx.lifecycle.repeatOnLifecycle
20import androidx.navigation.findNavController 20import androidx.navigation.findNavController
21import androidx.navigation.fragment.navArgs 21import androidx.navigation.fragment.navArgs
22import androidx.recyclerview.widget.LinearLayoutManager 22import androidx.recyclerview.widget.LinearLayoutManager
23import com.google.android.material.divider.MaterialDividerItemDecoration
24import com.google.android.material.transition.MaterialSharedAxis 23import com.google.android.material.transition.MaterialSharedAxis
25import kotlinx.coroutines.flow.collectLatest 24import kotlinx.coroutines.flow.collectLatest
26import kotlinx.coroutines.launch 25import kotlinx.coroutines.launch
@@ -68,15 +67,9 @@ class SettingsFragment : Fragment() {
68 ) 67 )
69 68
70 binding.toolbarSettingsLayout.title = getString(args.menuTag.titleId) 69 binding.toolbarSettingsLayout.title = getString(args.menuTag.titleId)
71 val dividerDecoration = MaterialDividerItemDecoration(
72 requireContext(),
73 LinearLayoutManager.VERTICAL
74 )
75 dividerDecoration.isLastItemDecorated = false
76 binding.listSettings.apply { 70 binding.listSettings.apply {
77 adapter = settingsAdapter 71 adapter = settingsAdapter
78 layoutManager = LinearLayoutManager(requireContext()) 72 layoutManager = LinearLayoutManager(requireContext())
79 addItemDecoration(dividerDecoration)
80 } 73 }
81 74
82 binding.toolbarSettings.setNavigationOnClickListener { 75 binding.toolbarSettings.setNavigationOnClickListener {
@@ -94,17 +87,6 @@ class SettingsFragment : Fragment() {
94 } 87 }
95 } 88 }
96 } 89 }
97 launch {
98 settingsViewModel.isUsingSearch.collectLatest {
99 if (it) {
100 reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
101 exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
102 } else {
103 reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
104 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
105 }
106 }
107 }
108 } 90 }
109 91
110 if (args.menuTag == Settings.MenuTag.SECTION_ROOT) { 92 if (args.menuTag == Settings.MenuTag.SECTION_ROOT) {
@@ -112,8 +94,6 @@ class SettingsFragment : Fragment() {
112 binding.toolbarSettings.setOnMenuItemClickListener { 94 binding.toolbarSettings.setOnMenuItemClickListener {
113 when (it.itemId) { 95 when (it.itemId) {
114 R.id.action_search -> { 96 R.id.action_search -> {
115 reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true)
116 exitTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
117 view.findNavController() 97 view.findNavController()
118 .navigate(R.id.action_settingsFragment_to_settingsSearchFragment) 98 .navigate(R.id.action_settingsFragment_to_settingsSearchFragment)
119 true 99 true
@@ -129,11 +109,6 @@ class SettingsFragment : Fragment() {
129 setInsets() 109 setInsets()
130 } 110 }
131 111
132 override fun onResume() {
133 super.onResume()
134 settingsViewModel.setIsUsingSearch(false)
135 }
136
137 private fun setInsets() { 112 private fun setInsets() {
138 ViewCompat.setOnApplyWindowInsetsListener( 113 ViewCompat.setOnApplyWindowInsetsListener(
139 binding.root 114 binding.root
@@ -144,10 +119,9 @@ class SettingsFragment : Fragment() {
144 val leftInsets = barInsets.left + cutoutInsets.left 119 val leftInsets = barInsets.left + cutoutInsets.left
145 val rightInsets = barInsets.right + cutoutInsets.right 120 val rightInsets = barInsets.right + cutoutInsets.right
146 121
147 val sideMargin = resources.getDimensionPixelSize(R.dimen.spacing_medlarge)
148 val mlpSettingsList = binding.listSettings.layoutParams as MarginLayoutParams 122 val mlpSettingsList = binding.listSettings.layoutParams as MarginLayoutParams
149 mlpSettingsList.leftMargin = sideMargin + leftInsets 123 mlpSettingsList.leftMargin = leftInsets
150 mlpSettingsList.rightMargin = sideMargin + rightInsets 124 mlpSettingsList.rightMargin = rightInsets
151 binding.listSettings.layoutParams = mlpSettingsList 125 binding.listSettings.layoutParams = mlpSettingsList
152 binding.listSettings.updatePadding( 126 binding.listSettings.updatePadding(
153 bottom = barInsets.bottom 127 bottom = barInsets.bottom
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index 766414a6c..8b71e32f3 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -3,7 +3,6 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.ui 4package org.yuzu.yuzu_emu.features.settings.ui
5 5
6import android.content.Context
7import android.content.SharedPreferences 6import android.content.SharedPreferences
8import android.os.Build 7import android.os.Build
9import android.widget.Toast 8import android.widget.Toast
@@ -32,8 +31,6 @@ class SettingsFragmentPresenter(
32 private val preferences: SharedPreferences 31 private val preferences: SharedPreferences
33 get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) 32 get() = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
34 33
35 private val context: Context get() = YuzuApplication.appContext
36
37 // Extension for populating settings list based on paired settings 34 // Extension for populating settings list based on paired settings
38 fun ArrayList<SettingsItem>.add(key: String) { 35 fun ArrayList<SettingsItem>.add(key: String) {
39 val item = SettingsItem.settingsItems[key]!! 36 val item = SettingsItem.settingsItems[key]!!
@@ -53,7 +50,6 @@ class SettingsFragmentPresenter(
53 val sl = ArrayList<SettingsItem>() 50 val sl = ArrayList<SettingsItem>()
54 when (menuTag) { 51 when (menuTag) {
55 Settings.MenuTag.SECTION_ROOT -> addConfigSettings(sl) 52 Settings.MenuTag.SECTION_ROOT -> addConfigSettings(sl)
56 Settings.MenuTag.SECTION_GENERAL -> addGeneralSettings(sl)
57 Settings.MenuTag.SECTION_SYSTEM -> addSystemSettings(sl) 53 Settings.MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
58 Settings.MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl) 54 Settings.MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
59 Settings.MenuTag.SECTION_AUDIO -> addAudioSettings(sl) 55 Settings.MenuTag.SECTION_AUDIO -> addAudioSettings(sl)
@@ -75,30 +71,53 @@ class SettingsFragmentPresenter(
75 71
76 private fun addConfigSettings(sl: ArrayList<SettingsItem>) { 72 private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
77 sl.apply { 73 sl.apply {
78 add(SubmenuSetting(R.string.preferences_general, 0, Settings.MenuTag.SECTION_GENERAL))
79 add(SubmenuSetting(R.string.preferences_system, 0, Settings.MenuTag.SECTION_SYSTEM))
80 add(SubmenuSetting(R.string.preferences_graphics, 0, Settings.MenuTag.SECTION_RENDERER))
81 add(SubmenuSetting(R.string.preferences_audio, 0, Settings.MenuTag.SECTION_AUDIO))
82 add(SubmenuSetting(R.string.preferences_debug, 0, Settings.MenuTag.SECTION_DEBUG))
83 add( 74 add(
84 RunnableSetting(R.string.reset_to_default, 0, false) { 75 SubmenuSetting(
85 settingsViewModel.setShouldShowResetSettingsDialog(true) 76 R.string.preferences_system,
86 } 77 R.string.preferences_system_description,
78 R.drawable.ic_system_settings,
79 Settings.MenuTag.SECTION_SYSTEM
80 )
81 )
82 add(
83 SubmenuSetting(
84 R.string.preferences_graphics,
85 R.string.preferences_graphics_description,
86 R.drawable.ic_graphics,
87 Settings.MenuTag.SECTION_RENDERER
88 )
89 )
90 add(
91 SubmenuSetting(
92 R.string.preferences_audio,
93 R.string.preferences_audio_description,
94 R.drawable.ic_audio,
95 Settings.MenuTag.SECTION_AUDIO
96 )
97 )
98 add(
99 SubmenuSetting(
100 R.string.preferences_debug,
101 R.string.preferences_debug_description,
102 R.drawable.ic_code,
103 Settings.MenuTag.SECTION_DEBUG
104 )
105 )
106 add(
107 RunnableSetting(
108 R.string.reset_to_default,
109 R.string.reset_to_default_description,
110 false,
111 R.drawable.ic_restore
112 ) { settingsViewModel.setShouldShowResetSettingsDialog(true) }
87 ) 113 )
88 } 114 }
89 } 115 }
90 116
91 private fun addGeneralSettings(sl: ArrayList<SettingsItem>) { 117 private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
92 sl.apply { 118 sl.apply {
93 add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key) 119 add(BooleanSetting.RENDERER_USE_SPEED_LIMIT.key)
94 add(ShortSetting.RENDERER_SPEED_LIMIT.key) 120 add(ShortSetting.RENDERER_SPEED_LIMIT.key)
95 add(IntSetting.CPU_ACCURACY.key)
96 add(BooleanSetting.PICTURE_IN_PICTURE.key)
97 }
98 }
99
100 private fun addSystemSettings(sl: ArrayList<SettingsItem>) {
101 sl.apply {
102 add(BooleanSetting.USE_DOCKED_MODE.key) 121 add(BooleanSetting.USE_DOCKED_MODE.key)
103 add(IntSetting.REGION_INDEX.key) 122 add(IntSetting.REGION_INDEX.key)
104 add(IntSetting.LANGUAGE_INDEX.key) 123 add(IntSetting.LANGUAGE_INDEX.key)
@@ -116,6 +135,7 @@ class SettingsFragmentPresenter(
116 add(IntSetting.RENDERER_ANTI_ALIASING.key) 135 add(IntSetting.RENDERER_ANTI_ALIASING.key)
117 add(IntSetting.RENDERER_SCREEN_LAYOUT.key) 136 add(IntSetting.RENDERER_SCREEN_LAYOUT.key)
118 add(IntSetting.RENDERER_ASPECT_RATIO.key) 137 add(IntSetting.RENDERER_ASPECT_RATIO.key)
138 add(BooleanSetting.PICTURE_IN_PICTURE.key)
119 add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key) 139 add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
120 add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key) 140 add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
121 add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key) 141 add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
@@ -249,6 +269,7 @@ class SettingsFragmentPresenter(
249 add(BooleanSetting.RENDERER_DEBUG.key) 269 add(BooleanSetting.RENDERER_DEBUG.key)
250 270
251 add(HeaderSetting(R.string.cpu)) 271 add(HeaderSetting(R.string.cpu))
272 add(IntSetting.CPU_ACCURACY.key)
252 add(BooleanSetting.CPU_DEBUG_MODE.key) 273 add(BooleanSetting.CPU_DEBUG_MODE.key)
253 add(SettingsItem.FASTMEM_COMBINED) 274 add(SettingsItem.FASTMEM_COMBINED)
254 } 275 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt
index 83a2e94f1..036195624 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/RunnableViewHolder.kt
@@ -4,6 +4,7 @@
4package org.yuzu.yuzu_emu.features.settings.ui.viewholder 4package org.yuzu.yuzu_emu.features.settings.ui.viewholder
5 5
6import android.view.View 6import android.view.View
7import androidx.core.content.res.ResourcesCompat
7import org.yuzu.yuzu_emu.NativeLibrary 8import org.yuzu.yuzu_emu.NativeLibrary
8import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding 9import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
9import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting 10import org.yuzu.yuzu_emu.features.settings.model.view.RunnableSetting
@@ -16,6 +17,19 @@ class RunnableViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA
16 17
17 override fun bind(item: SettingsItem) { 18 override fun bind(item: SettingsItem) {
18 setting = item as RunnableSetting 19 setting = item as RunnableSetting
20 if (item.iconId != 0) {
21 binding.icon.visibility = View.VISIBLE
22 binding.icon.setImageDrawable(
23 ResourcesCompat.getDrawable(
24 binding.icon.resources,
25 item.iconId,
26 binding.icon.context.theme
27 )
28 )
29 } else {
30 binding.icon.visibility = View.GONE
31 }
32
19 binding.textSettingName.setText(item.nameId) 33 binding.textSettingName.setText(item.nameId)
20 if (item.descriptionId != 0) { 34 if (item.descriptionId != 0) {
21 binding.textSettingDescription.setText(item.descriptionId) 35 binding.textSettingDescription.setText(item.descriptionId)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt
index 1cf581a9d..8100c65dd 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SubmenuViewHolder.kt
@@ -4,6 +4,7 @@
4package org.yuzu.yuzu_emu.features.settings.ui.viewholder 4package org.yuzu.yuzu_emu.features.settings.ui.viewholder
5 5
6import android.view.View 6import android.view.View
7import androidx.core.content.res.ResourcesCompat
7import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding 8import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
8import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
9import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting 10import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting
@@ -15,6 +16,19 @@ class SubmenuViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAd
15 16
16 override fun bind(item: SettingsItem) { 17 override fun bind(item: SettingsItem) {
17 this.item = item as SubmenuSetting 18 this.item = item as SubmenuSetting
19 if (item.iconId != 0) {
20 binding.icon.visibility = View.VISIBLE
21 binding.icon.setImageDrawable(
22 ResourcesCompat.getDrawable(
23 binding.icon.resources,
24 item.iconId,
25 binding.icon.context.theme
26 )
27 )
28 } else {
29 binding.icon.visibility = View.GONE
30 }
31
18 binding.textSettingName.setText(item.nameId) 32 binding.textSettingName.setText(item.nameId)
19 if (item.descriptionId != 0) { 33 if (item.descriptionId != 0) {
20 binding.textSettingDescription.setText(item.descriptionId) 34 binding.textSettingDescription.setText(item.descriptionId)
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 2ff827c6b..a1620fbb7 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
@@ -114,10 +114,10 @@ class AboutFragment : Fragment() {
114 val leftInsets = barInsets.left + cutoutInsets.left 114 val leftInsets = barInsets.left + cutoutInsets.left
115 val rightInsets = barInsets.right + cutoutInsets.right 115 val rightInsets = barInsets.right + cutoutInsets.right
116 116
117 val mlpAppBar = binding.appbarAbout.layoutParams as MarginLayoutParams 117 val mlpToolbar = binding.toolbarAbout.layoutParams as MarginLayoutParams
118 mlpAppBar.leftMargin = leftInsets 118 mlpToolbar.leftMargin = leftInsets
119 mlpAppBar.rightMargin = rightInsets 119 mlpToolbar.rightMargin = rightInsets
120 binding.appbarAbout.layoutParams = mlpAppBar 120 binding.toolbarAbout.layoutParams = mlpToolbar
121 121
122 val mlpScrollAbout = binding.scrollAbout.layoutParams as MarginLayoutParams 122 val mlpScrollAbout = binding.scrollAbout.layoutParams as MarginLayoutParams
123 mlpScrollAbout.leftMargin = leftInsets 123 mlpScrollAbout.leftMargin = leftInsets
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt
index 9d0594c6e..f95d545bf 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SettingsSearchFragment.kt
@@ -40,8 +40,10 @@ class SettingsSearchFragment : Fragment() {
40 40
41 override fun onCreate(savedInstanceState: Bundle?) { 41 override fun onCreate(savedInstanceState: Bundle?) {
42 super.onCreate(savedInstanceState) 42 super.onCreate(savedInstanceState)
43 enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) 43 enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
44 returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true) 44 returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
45 reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
46 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
45 } 47 }
46 48
47 override fun onCreateView( 49 override fun onCreateView(
@@ -55,7 +57,6 @@ class SettingsSearchFragment : Fragment() {
55 57
56 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 58 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
57 super.onViewCreated(view, savedInstanceState) 59 super.onViewCreated(view, savedInstanceState)
58 settingsViewModel.setIsUsingSearch(true)
59 60
60 if (savedInstanceState != null) { 61 if (savedInstanceState != null) {
61 binding.searchText.setText(savedInstanceState.getString(SEARCH_TEXT)) 62 binding.searchText.setText(savedInstanceState.getString(SEARCH_TEXT))
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt
index 53fa7a8de..6f947674e 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/SettingsViewModel.kt
@@ -29,9 +29,6 @@ class SettingsViewModel : ViewModel() {
29 val shouldReloadSettingsList: StateFlow<Boolean> get() = _shouldReloadSettingsList 29 val shouldReloadSettingsList: StateFlow<Boolean> get() = _shouldReloadSettingsList
30 private val _shouldReloadSettingsList = MutableStateFlow(false) 30 private val _shouldReloadSettingsList = MutableStateFlow(false)
31 31
32 val isUsingSearch: StateFlow<Boolean> get() = _isUsingSearch
33 private val _isUsingSearch = MutableStateFlow(false)
34
35 val sliderProgress: StateFlow<Int> get() = _sliderProgress 32 val sliderProgress: StateFlow<Int> get() = _sliderProgress
36 private val _sliderProgress = MutableStateFlow(-1) 33 private val _sliderProgress = MutableStateFlow(-1)
37 34
@@ -57,10 +54,6 @@ class SettingsViewModel : ViewModel() {
57 _shouldReloadSettingsList.value = value 54 _shouldReloadSettingsList.value = value
58 } 55 }
59 56
60 fun setIsUsingSearch(value: Boolean) {
61 _isUsingSearch.value = value
62 }
63
64 fun setSliderTextValue(value: Float, units: String) { 57 fun setSliderTextValue(value: Float, units: String) {
65 _sliderProgress.value = value.toInt() 58 _sliderProgress.value = value.toInt()
66 _sliderTextValue.value = String.format( 59 _sliderTextValue.value = String.format(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt
index 654d62f52..2e9b0beb8 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameIconUtils.kt
@@ -8,9 +8,9 @@ import android.graphics.BitmapFactory
8import android.widget.ImageView 8import android.widget.ImageView
9import androidx.core.graphics.drawable.toBitmap 9import androidx.core.graphics.drawable.toBitmap
10import androidx.core.graphics.drawable.toDrawable 10import androidx.core.graphics.drawable.toDrawable
11import androidx.lifecycle.LifecycleOwner
11import coil.ImageLoader 12import coil.ImageLoader
12import coil.decode.DataSource 13import coil.decode.DataSource
13import coil.executeBlocking
14import coil.fetch.DrawableResult 14import coil.fetch.DrawableResult
15import coil.fetch.FetchResult 15import coil.fetch.FetchResult
16import coil.fetch.Fetcher 16import coil.fetch.Fetcher
@@ -76,12 +76,13 @@ object GameIconUtils {
76 imageLoader.enqueue(request) 76 imageLoader.enqueue(request)
77 } 77 }
78 78
79 fun getGameIcon(game: Game): Bitmap { 79 suspend fun getGameIcon(lifecycleOwner: LifecycleOwner, game: Game): Bitmap {
80 val request = ImageRequest.Builder(YuzuApplication.appContext) 80 val request = ImageRequest.Builder(YuzuApplication.appContext)
81 .data(game) 81 .data(game)
82 .lifecycle(lifecycleOwner)
82 .error(R.drawable.default_icon) 83 .error(R.drawable.default_icon)
83 .build() 84 .build()
84 return imageLoader.executeBlocking(request) 85 return imageLoader.execute(request)
85 .drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888) 86 .drawable!!.toBitmap(config = Bitmap.Config.ARGB_8888)
86 } 87 }
87} 88}
diff --git a/src/android/app/src/main/jni/uisettings.h b/src/android/app/src/main/jni/uisettings.h
index 494654af7..37bc33918 100644
--- a/src/android/app/src/main/jni/uisettings.h
+++ b/src/android/app/src/main/jni/uisettings.h
@@ -13,7 +13,7 @@ struct Values {
13 Settings::Linkage linkage; 13 Settings::Linkage linkage;
14 14
15 // Android 15 // Android
16 Settings::Setting<bool> picture_in_picture{linkage, true, "picture_in_picture", 16 Settings::Setting<bool> picture_in_picture{linkage, false, "picture_in_picture",
17 Settings::Category::Android}; 17 Settings::Category::Android};
18 Settings::Setting<s32> screen_layout{linkage, 18 Settings::Setting<s32> screen_layout{linkage,
19 5, 19 5,
diff --git a/src/android/app/src/main/res/drawable/ic_audio.xml b/src/android/app/src/main/res/drawable/ic_audio.xml
new file mode 100644
index 000000000..e306c3b0c
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_audio.xml
@@ -0,0 +1,9 @@
1<vector xmlns:android="http://schemas.android.com/apk/res/android"
2 android:width="24dp"
3 android:height="24dp"
4 android:viewportHeight="24"
5 android:viewportWidth="24">
6 <path
7 android:fillColor="?attr/colorControlNormal"
8 android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z" />
9</vector>
diff --git a/src/android/app/src/main/res/drawable/ic_code.xml b/src/android/app/src/main/res/drawable/ic_code.xml
new file mode 100644
index 000000000..26f83b39b
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_code.xml
@@ -0,0 +1,9 @@
1<vector xmlns:android="http://schemas.android.com/apk/res/android"
2 android:width="24dp"
3 android:height="24dp"
4 android:viewportWidth="960"
5 android:viewportHeight="960">
6 <path
7 android:fillColor="?attr/colorControlNormal"
8 android:pathData="M320,720 L80,480l240,-240 57,57 -184,184 183,183 -56,56ZM640,720 L583,663 767,479 584,296 640,240 880,480 640,720Z"/>
9</vector>
diff --git a/src/android/app/src/main/res/drawable/ic_graphics.xml b/src/android/app/src/main/res/drawable/ic_graphics.xml
new file mode 100644
index 000000000..2fdb5a4d6
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_graphics.xml
@@ -0,0 +1,9 @@
1<vector xmlns:android="http://schemas.android.com/apk/res/android"
2 android:width="24dp"
3 android:height="24dp"
4 android:viewportWidth="960"
5 android:viewportHeight="960">
6 <path
7 android:fillColor="?attr/colorControlNormal"
8 android:pathData="M160,840q-33,0 -56.5,-23.5T80,760v-560q0,-33 23.5,-56.5T160,120h560q33,0 56.5,23.5T800,200v80h80v80h-80v80h80v80h-80v80h80v80h-80v80q0,33 -23.5,56.5T720,840L160,840ZM160,760h560v-560L160,200v560ZM240,680h200v-160L240,520v160ZM480,400h160v-120L480,280v120ZM240,480h200v-200L240,280v200ZM480,680h160v-240L480,440v240ZM160,200v560,-560Z"/>
9</vector>
diff --git a/src/android/app/src/main/res/drawable/ic_system_settings.xml b/src/android/app/src/main/res/drawable/ic_system_settings.xml
new file mode 100644
index 000000000..7701a2bab
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_system_settings.xml
@@ -0,0 +1,9 @@
1<vector xmlns:android="http://schemas.android.com/apk/res/android"
2 android:width="24dp"
3 android:height="24dp"
4 android:viewportWidth="960"
5 android:viewportHeight="960">
6 <path
7 android:fillColor="?attr/colorControlNormal"
8 android:pathData="M320,960q-17,0 -28.5,-11.5T280,920q0,-17 11.5,-28.5T320,880q17,0 28.5,11.5T360,920q0,17 -11.5,28.5T320,960ZM480,960q-17,0 -28.5,-11.5T440,920q0,-17 11.5,-28.5T480,880q17,0 28.5,11.5T520,920q0,17 -11.5,28.5T480,960ZM640,960q-17,0 -28.5,-11.5T600,920q0,-17 11.5,-28.5T640,880q17,0 28.5,11.5T680,920q0,17 -11.5,28.5T640,960ZM320,800q-33,0 -56.5,-23.5T240,720v-640q0,-33 23.5,-56.5T320,0h320q33,0 56.5,23.5T720,80v640q0,33 -23.5,56.5T640,800L320,800ZM320,720h320v-40L320,680v40ZM320,600h320v-400L320,200v400ZM320,120h320v-40L320,80v40ZM320,120v-40,40ZM320,720v-40,40Z"/>
9</vector>
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
new file mode 100644
index 000000000..a26ffbc73
--- /dev/null
+++ b/src/android/app/src/main/res/layout-w600dp/fragment_about.xml
@@ -0,0 +1,233 @@
1<?xml version="1.0" encoding="utf-8"?>
2<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:id="@+id/coordinator_about"
6 android:layout_width="match_parent"
7 android:layout_height="match_parent"
8 android:background="?attr/colorSurface">
9
10 <com.google.android.material.appbar.AppBarLayout
11 android:id="@+id/appbar_about"
12 android:layout_width="match_parent"
13 android:layout_height="wrap_content"
14 android:fitsSystemWindows="true">
15
16 <com.google.android.material.appbar.MaterialToolbar
17 android:id="@+id/toolbar_about"
18 android:layout_width="match_parent"
19 android:layout_height="?attr/actionBarSize"
20 app:navigationIcon="@drawable/ic_back"
21 app:title="@string/about" />
22
23 </com.google.android.material.appbar.AppBarLayout>
24
25 <androidx.core.widget.NestedScrollView
26 android:id="@+id/scroll_about"
27 android:layout_width="match_parent"
28 android:layout_height="match_parent"
29 android:fadeScrollbars="false"
30 android:scrollbars="vertical"
31 app:layout_behavior="@string/appbar_scrolling_view_behavior">
32
33 <LinearLayout
34 android:id="@+id/content_about"
35 android:layout_width="match_parent"
36 android:layout_height="match_parent"
37 android:orientation="horizontal">
38
39 <ImageView
40 android:id="@+id/image_logo"
41 android:layout_width="200dp"
42 android:layout_height="200dp"
43 android:layout_gravity="center_horizontal"
44 android:padding="20dp"
45 android:src="@drawable/ic_yuzu_title" />
46
47 <LinearLayout
48 android:layout_width="wrap_content"
49 android:layout_height="wrap_content"
50 android:orientation="vertical">
51
52 <LinearLayout
53 android:layout_width="match_parent"
54 android:layout_height="wrap_content"
55 android:orientation="vertical"
56 android:paddingHorizontal="16dp"
57 android:paddingVertical="16dp">
58
59 <com.google.android.material.textview.MaterialTextView
60 style="@style/TextAppearance.Material3.TitleMedium"
61 android:layout_width="match_parent"
62 android:layout_height="wrap_content"
63 android:layout_marginHorizontal="24dp"
64 android:text="@string/about"
65 android:textAlignment="viewStart" />
66
67 <com.google.android.material.textview.MaterialTextView
68 style="@style/TextAppearance.Material3.BodyMedium"
69 android:layout_width="match_parent"
70 android:layout_height="wrap_content"
71 android:layout_marginHorizontal="24dp"
72 android:layout_marginTop="6dp"
73 android:text="@string/about_app_description"
74 android:textAlignment="viewStart" />
75
76 </LinearLayout>
77
78 <com.google.android.material.divider.MaterialDivider
79 android:layout_width="match_parent"
80 android:layout_height="wrap_content"
81 android:layout_marginHorizontal="20dp" />
82
83 <LinearLayout
84 android:id="@+id/button_contributors"
85 android:layout_width="match_parent"
86 android:layout_height="wrap_content"
87 android:background="?attr/selectableItemBackground"
88 android:orientation="vertical"
89 android:paddingHorizontal="16dp"
90 android:paddingVertical="16dp">
91
92 <com.google.android.material.textview.MaterialTextView
93 style="@style/TextAppearance.Material3.TitleMedium"
94 android:layout_width="match_parent"
95 android:layout_height="wrap_content"
96 android:layout_marginHorizontal="24dp"
97 android:text="@string/contributors"
98 android:textAlignment="viewStart" />
99
100 <com.google.android.material.textview.MaterialTextView
101 style="@style/TextAppearance.Material3.BodyMedium"
102 android:layout_width="match_parent"
103 android:layout_height="wrap_content"
104 android:layout_marginHorizontal="24dp"
105 android:layout_marginTop="6dp"
106 android:text="@string/contributors_description"
107 android:textAlignment="viewStart" />
108
109 </LinearLayout>
110
111 <com.google.android.material.divider.MaterialDivider
112 android:layout_width="match_parent"
113 android:layout_height="wrap_content"
114 android:layout_marginHorizontal="20dp" />
115
116 <LinearLayout
117 android:id="@+id/button_licenses"
118 android:layout_width="match_parent"
119 android:layout_height="wrap_content"
120 android:background="?attr/selectableItemBackground"
121 android:orientation="vertical"
122 android:paddingHorizontal="16dp"
123 android:paddingVertical="16dp">
124
125 <com.google.android.material.textview.MaterialTextView
126 style="@style/TextAppearance.Material3.TitleMedium"
127 android:layout_width="match_parent"
128 android:layout_height="wrap_content"
129 android:layout_marginHorizontal="24dp"
130 android:text="@string/licenses"
131 android:textAlignment="viewStart" />
132
133 <com.google.android.material.textview.MaterialTextView
134 style="@style/TextAppearance.Material3.BodyMedium"
135 android:layout_width="match_parent"
136 android:layout_height="wrap_content"
137 android:layout_marginHorizontal="24dp"
138 android:layout_marginTop="6dp"
139 android:text="@string/licenses_description"
140 android:textAlignment="viewStart" />
141
142 </LinearLayout>
143
144 <com.google.android.material.divider.MaterialDivider
145 android:layout_width="match_parent"
146 android:layout_height="wrap_content"
147 android:layout_marginHorizontal="20dp" />
148
149 <LinearLayout
150 android:id="@+id/button_build_hash"
151 android:layout_width="match_parent"
152 android:layout_height="wrap_content"
153 android:background="?attr/selectableItemBackground"
154 android:orientation="vertical"
155 android:paddingHorizontal="16dp"
156 android:paddingVertical="16dp">
157
158 <com.google.android.material.textview.MaterialTextView
159 style="@style/TextAppearance.Material3.TitleMedium"
160 android:layout_width="match_parent"
161 android:layout_height="wrap_content"
162 android:layout_marginHorizontal="24dp"
163 android:text="@string/build"
164 android:textAlignment="viewStart" />
165
166 <com.google.android.material.textview.MaterialTextView
167 android:id="@+id/text_build_hash"
168 style="@style/TextAppearance.Material3.BodyMedium"
169 android:layout_width="match_parent"
170 android:layout_height="wrap_content"
171 android:layout_marginHorizontal="24dp"
172 android:layout_marginTop="6dp"
173 android:textAlignment="viewStart"
174 tools:text="abc123" />
175
176 </LinearLayout>
177
178 <com.google.android.material.divider.MaterialDivider
179 android:layout_width="match_parent"
180 android:layout_height="wrap_content"
181 android:layout_marginHorizontal="20dp" />
182
183 <LinearLayout
184 android:layout_width="match_parent"
185 android:layout_height="wrap_content"
186 android:layout_marginHorizontal="40dp"
187 android:layout_marginTop="12dp"
188 android:layout_marginBottom="16dp"
189 android:gravity="center_horizontal"
190 android:orientation="horizontal">
191
192 <Button
193 android:id="@+id/button_discord"
194 style="?attr/materialIconButtonStyle"
195 android:layout_width="0dp"
196 android:layout_height="wrap_content"
197 android:layout_weight="1"
198 app:icon="@drawable/ic_discord"
199 app:iconGravity="textEnd"
200 app:iconSize="24dp"
201 app:iconTint="?attr/colorOnSurface" />
202
203 <Button
204 android:id="@+id/button_website"
205 style="?attr/materialIconButtonStyle"
206 android:layout_width="0dp"
207 android:layout_height="wrap_content"
208 android:layout_weight="1"
209 app:icon="@drawable/ic_website"
210 app:iconGravity="textEnd"
211 app:iconSize="24dp"
212 app:iconTint="?attr/colorOnSurface" />
213
214 <Button
215 android:id="@+id/button_github"
216 style="?attr/materialIconButtonStyle"
217 android:layout_width="0dp"
218 android:layout_height="wrap_content"
219 android:layout_weight="1"
220 app:icon="@drawable/ic_github"
221 app:iconGravity="textEnd"
222 app:iconSize="24dp"
223 app:iconTint="?attr/colorOnSurface" />
224
225 </LinearLayout>
226
227 </LinearLayout>
228
229 </LinearLayout>
230
231 </androidx.core.widget.NestedScrollView>
232
233</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/src/android/app/src/main/res/layout/card_home_option.xml b/src/android/app/src/main/res/layout/card_home_option.xml
index 6e8a232f9..cb667c928 100644
--- a/src/android/app/src/main/res/layout/card_home_option.xml
+++ b/src/android/app/src/main/res/layout/card_home_option.xml
@@ -6,8 +6,8 @@
6 android:id="@+id/option_card" 6 android:id="@+id/option_card"
7 android:layout_width="match_parent" 7 android:layout_width="match_parent"
8 android:layout_height="wrap_content" 8 android:layout_height="wrap_content"
9 android:layout_marginVertical="12dp" 9 android:layout_marginBottom="24dp"
10 android:layout_marginHorizontal="16dp" 10 android:layout_marginHorizontal="12dp"
11 android:background="?attr/selectableItemBackground" 11 android:background="?attr/selectableItemBackground"
12 android:backgroundTint="?attr/colorSurfaceVariant" 12 android:backgroundTint="?attr/colorSurfaceVariant"
13 android:clickable="true" 13 android:clickable="true"
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 3e1d98451..a24f5230e 100644
--- a/src/android/app/src/main/res/layout/fragment_about.xml
+++ b/src/android/app/src/main/res/layout/fragment_about.xml
@@ -38,17 +38,17 @@
38 38
39 <ImageView 39 <ImageView
40 android:id="@+id/image_logo" 40 android:id="@+id/image_logo"
41 android:layout_width="250dp" 41 android:layout_width="150dp"
42 android:layout_height="250dp" 42 android:layout_height="150dp"
43 android:layout_marginTop="20dp" 43 android:layout_marginTop="24dp"
44 android:layout_marginBottom="28dp"
44 android:layout_gravity="center_horizontal" 45 android:layout_gravity="center_horizontal"
45 android:src="@drawable/ic_yuzu_title" /> 46 android:src="@drawable/ic_yuzu_title" />
46 47
47 <com.google.android.material.divider.MaterialDivider 48 <com.google.android.material.divider.MaterialDivider
48 android:layout_width="match_parent" 49 android:layout_width="match_parent"
49 android:layout_height="wrap_content" 50 android:layout_height="wrap_content"
50 android:layout_marginHorizontal="20dp" 51 android:layout_marginHorizontal="20dp" />
51 android:layout_marginTop="28dp" />
52 52
53 <LinearLayout 53 <LinearLayout
54 android:layout_width="match_parent" 54 android:layout_width="match_parent"
diff --git a/src/android/app/src/main/res/layout/fragment_emulation.xml b/src/android/app/src/main/res/layout/fragment_emulation.xml
index cd6360b45..5252adf54 100644
--- a/src/android/app/src/main/res/layout/fragment_emulation.xml
+++ b/src/android/app/src/main/res/layout/fragment_emulation.xml
@@ -139,7 +139,7 @@
139 139
140 <com.google.android.material.textview.MaterialTextView 140 <com.google.android.material.textview.MaterialTextView
141 android:id="@+id/show_fps_text" 141 android:id="@+id/show_fps_text"
142 style="@style/TextAppearance.Material3.BodyMedium" 142 style="@style/TextAppearance.Material3.BodySmall"
143 android:layout_width="wrap_content" 143 android:layout_width="wrap_content"
144 android:layout_height="wrap_content" 144 android:layout_height="wrap_content"
145 android:layout_gravity="left" 145 android:layout_gravity="left"
@@ -147,7 +147,8 @@
147 android:focusable="false" 147 android:focusable="false"
148 android:paddingHorizontal="20dp" 148 android:paddingHorizontal="20dp"
149 android:textColor="@android:color/white" 149 android:textColor="@android:color/white"
150 android:textSize="12sp" 150 android:shadowColor="@android:color/black"
151 android:shadowRadius="3"
151 tools:ignore="RtlHardcoded" /> 152 tools:ignore="RtlHardcoded" />
152 153
153 </FrameLayout> 154 </FrameLayout>
diff --git a/src/android/app/src/main/res/layout/fragment_home_settings.xml b/src/android/app/src/main/res/layout/fragment_home_settings.xml
index 1cb421dcb..d84093ba3 100644
--- a/src/android/app/src/main/res/layout/fragment_home_settings.xml
+++ b/src/android/app/src/main/res/layout/fragment_home_settings.xml
@@ -14,13 +14,14 @@
14 android:layout_width="match_parent" 14 android:layout_width="match_parent"
15 android:layout_height="match_parent" 15 android:layout_height="match_parent"
16 android:orientation="vertical" 16 android:orientation="vertical"
17 android:background="?attr/colorSurface"> 17 android:background="?attr/colorSurface"
18 android:paddingHorizontal="8dp">
18 19
19 <ImageView 20 <ImageView
20 android:id="@+id/logo_image" 21 android:id="@+id/logo_image"
21 android:layout_width="128dp" 22 android:layout_width="96dp"
22 android:layout_height="128dp" 23 android:layout_height="96dp"
23 android:layout_margin="64dp" 24 android:layout_marginVertical="32dp"
24 android:layout_gravity="center_horizontal" 25 android:layout_gravity="center_horizontal"
25 android:src="@drawable/ic_yuzu_full" /> 26 android:src="@drawable/ic_yuzu_full" />
26 27
diff --git a/src/android/app/src/main/res/layout/list_item_setting.xml b/src/android/app/src/main/res/layout/list_item_setting.xml
index f1037a740..544280e75 100644
--- a/src/android/app/src/main/res/layout/list_item_setting.xml
+++ b/src/android/app/src/main/res/layout/list_item_setting.xml
@@ -10,41 +10,59 @@
10 android:focusable="true" 10 android:focusable="true"
11 android:gravity="center_vertical" 11 android:gravity="center_vertical"
12 android:minHeight="72dp" 12 android:minHeight="72dp"
13 android:padding="@dimen/spacing_large"> 13 android:padding="16dp">
14 14
15 <LinearLayout 15 <LinearLayout
16 android:layout_width="match_parent" 16 android:layout_width="match_parent"
17 android:layout_height="wrap_content" 17 android:layout_height="wrap_content"
18 android:orientation="vertical"> 18 android:orientation="horizontal">
19 19
20 <com.google.android.material.textview.MaterialTextView 20 <ImageView
21 android:id="@+id/text_setting_name" 21 android:id="@+id/icon"
22 style="@style/TextAppearance.Material3.HeadlineMedium" 22 android:layout_width="24dp"
23 android:layout_width="match_parent" 23 android:layout_height="24dp"
24 android:layout_height="wrap_content" 24 android:layout_marginStart="8dp"
25 android:textAlignment="viewStart" 25 android:layout_marginEnd="24dp"
26 android:textSize="16sp" 26 android:layout_gravity="center_vertical"
27 app:lineHeight="22dp" 27 android:visibility="gone"
28 tools:text="Setting Name" /> 28 app:tint="?attr/colorOnSurface" />
29
30 <com.google.android.material.textview.MaterialTextView
31 android:id="@+id/text_setting_description"
32 style="@style/TextAppearance.Material3.BodySmall"
33 android:layout_width="match_parent"
34 android:layout_height="wrap_content"
35 android:layout_marginTop="@dimen/spacing_small"
36 android:textAlignment="viewStart"
37 tools:text="@string/app_disclaimer" />
38 29
39 <com.google.android.material.textview.MaterialTextView 30 <LinearLayout
40 android:id="@+id/text_setting_value"
41 style="@style/TextAppearance.Material3.LabelMedium"
42 android:layout_width="match_parent" 31 android:layout_width="match_parent"
43 android:layout_height="wrap_content" 32 android:layout_height="wrap_content"
44 android:layout_marginTop="@dimen/spacing_small" 33 android:orientation="vertical">
45 android:textAlignment="viewStart" 34
46 android:textStyle="bold" 35 <com.google.android.material.textview.MaterialTextView
47 tools:text="1x" /> 36 android:id="@+id/text_setting_name"
37 style="@style/TextAppearance.Material3.HeadlineMedium"
38 android:layout_width="match_parent"
39 android:layout_height="wrap_content"
40 android:textAlignment="viewStart"
41 android:textSize="17sp"
42 app:lineHeight="22dp"
43 tools:text="Setting Name" />
44
45 <com.google.android.material.textview.MaterialTextView
46 android:id="@+id/text_setting_description"
47 style="@style/TextAppearance.Material3.BodySmall"
48 android:layout_width="match_parent"
49 android:layout_height="wrap_content"
50 android:layout_marginTop="@dimen/spacing_small"
51 android:textAlignment="viewStart"
52 tools:text="@string/app_disclaimer" />
53
54 <com.google.android.material.textview.MaterialTextView
55 android:id="@+id/text_setting_value"
56 style="@style/TextAppearance.Material3.LabelMedium"
57 android:layout_width="match_parent"
58 android:layout_height="wrap_content"
59 android:layout_marginTop="@dimen/spacing_small"
60 android:textAlignment="viewStart"
61 android:textStyle="bold"
62 android:textSize="13sp"
63 tools:text="1x" />
64
65 </LinearLayout>
48 66
49 </LinearLayout> 67 </LinearLayout>
50 68
diff --git a/src/android/app/src/main/res/layout/list_item_setting_switch.xml b/src/android/app/src/main/res/layout/list_item_setting_switch.xml
index a5767adee..a8f5aff78 100644
--- a/src/android/app/src/main/res/layout/list_item_setting_switch.xml
+++ b/src/android/app/src/main/res/layout/list_item_setting_switch.xml
@@ -8,9 +8,7 @@
8 android:clickable="true" 8 android:clickable="true"
9 android:focusable="true" 9 android:focusable="true"
10 android:minHeight="72dp" 10 android:minHeight="72dp"
11 android:paddingVertical="@dimen/spacing_large" 11 android:padding="16dp">
12 android:paddingStart="@dimen/spacing_large"
13 android:paddingEnd="24dp">
14 12
15 <com.google.android.material.materialswitch.MaterialSwitch 13 <com.google.android.material.materialswitch.MaterialSwitch
16 android:id="@+id/switch_widget" 14 android:id="@+id/switch_widget"
@@ -24,7 +22,7 @@
24 android:layout_height="wrap_content" 22 android:layout_height="wrap_content"
25 android:layout_alignParentTop="true" 23 android:layout_alignParentTop="true"
26 android:layout_centerVertical="true" 24 android:layout_centerVertical="true"
27 android:layout_marginEnd="@dimen/spacing_large" 25 android:layout_marginEnd="24dp"
28 android:layout_toStartOf="@+id/switch_widget" 26 android:layout_toStartOf="@+id/switch_widget"
29 android:gravity="center_vertical" 27 android:gravity="center_vertical"
30 android:orientation="vertical"> 28 android:orientation="vertical">
@@ -35,7 +33,7 @@
35 android:layout_width="wrap_content" 33 android:layout_width="wrap_content"
36 android:layout_height="wrap_content" 34 android:layout_height="wrap_content"
37 android:textAlignment="viewStart" 35 android:textAlignment="viewStart"
38 android:textSize="16sp" 36 android:textSize="17sp"
39 app:lineHeight="28dp" 37 app:lineHeight="28dp"
40 tools:text="@string/frame_limit_enable" /> 38 tools:text="@string/frame_limit_enable" />
41 39
diff --git a/src/android/app/src/main/res/layout/list_item_settings_header.xml b/src/android/app/src/main/res/layout/list_item_settings_header.xml
index cf85bc0da..21276b19e 100644
--- a/src/android/app/src/main/res/layout/list_item_settings_header.xml
+++ b/src/android/app/src/main/res/layout/list_item_settings_header.xml
@@ -7,7 +7,8 @@
7 android:layout_height="wrap_content" 7 android:layout_height="wrap_content"
8 android:layout_gravity="start|center_vertical" 8 android:layout_gravity="start|center_vertical"
9 android:paddingHorizontal="@dimen/spacing_large" 9 android:paddingHorizontal="@dimen/spacing_large"
10 android:paddingVertical="16dp" 10 android:paddingTop="16dp"
11 android:paddingBottom="8dp"
11 android:textAlignment="viewStart" 12 android:textAlignment="viewStart"
12 android:textColor="?attr/colorPrimary" 13 android:textColor="?attr/colorPrimary"
13 android:textStyle="bold" 14 android:textStyle="bold"
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml
index dc10159c9..51bcc49a3 100644
--- a/src/android/app/src/main/res/values/arrays.xml
+++ b/src/android/app/src/main/res/values/arrays.xml
@@ -2,7 +2,6 @@
2<resources> 2<resources>
3 3
4 <string-array name="regionNames"> 4 <string-array name="regionNames">
5 <item>@string/auto</item>
6 <item>@string/region_australia</item> 5 <item>@string/region_australia</item>
7 <item>@string/region_china</item> 6 <item>@string/region_china</item>
8 <item>@string/region_europe</item> 7 <item>@string/region_europe</item>
@@ -13,7 +12,6 @@
13 </string-array> 12 </string-array>
14 13
15 <integer-array name="regionValues"> 14 <integer-array name="regionValues">
16 <item>-1</item>
17 <item>3</item> 15 <item>3</item>
18 <item>4</item> 16 <item>4</item>
19 <item>2</item> 17 <item>2</item>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index c551a6106..98c3f20f8 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -240,6 +240,7 @@
240 <string name="shutting_down">Shutting down…</string> 240 <string name="shutting_down">Shutting down…</string>
241 <string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string> 241 <string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string>
242 <string name="reset_to_default">Reset to default</string> 242 <string name="reset_to_default">Reset to default</string>
243 <string name="reset_to_default_description">Resets all advanced settings</string>
243 <string name="reset_all_settings">Reset all settings?</string> 244 <string name="reset_all_settings">Reset all settings?</string>
244 <string name="reset_all_settings_description">All advanced settings will be reset to their default configuration. This can not be undone.</string> 245 <string name="reset_all_settings_description">All advanced settings will be reset to their default configuration. This can not be undone.</string>
245 <string name="settings_reset">Settings reset</string> 246 <string name="settings_reset">Settings reset</string>
@@ -271,10 +272,14 @@
271 <string name="preferences_settings">Settings</string> 272 <string name="preferences_settings">Settings</string>
272 <string name="preferences_general">General</string> 273 <string name="preferences_general">General</string>
273 <string name="preferences_system">System</string> 274 <string name="preferences_system">System</string>
275 <string name="preferences_system_description">Docked mode, region, language</string>
274 <string name="preferences_graphics">Graphics</string> 276 <string name="preferences_graphics">Graphics</string>
277 <string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
275 <string name="preferences_audio">Audio</string> 278 <string name="preferences_audio">Audio</string>
279 <string name="preferences_audio_description">Output engine, volume</string>
276 <string name="preferences_theme">Theme and color</string> 280 <string name="preferences_theme">Theme and color</string>
277 <string name="preferences_debug">Debug</string> 281 <string name="preferences_debug">Debug</string>
282 <string name="preferences_debug_description">CPU/GPU debugging, graphics API, fastmem</string>
278 283
279 <!-- ROM loading errors --> 284 <!-- ROM loading errors -->
280 <string name="loader_error_encrypted">Your ROM is encrypted</string> 285 <string name="loader_error_encrypted">Your ROM is encrypted</string>
diff --git a/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp b/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp
index 7f1ed0450..05cf3975d 100644
--- a/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp
+++ b/src/audio_core/adsp/apps/opus/opus_multistream_decode_object.cpp
@@ -12,7 +12,7 @@ bool IsValidChannelCount(u32 channel_count) {
12} 12}
13 13
14bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) { 14bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
15 return total_stream_count > 0 && stereo_stream_count > 0 && 15 return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
16 stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count); 16 stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
17} 17}
18} // namespace 18} // namespace
diff --git a/src/audio_core/opus/decoder.cpp b/src/audio_core/opus/decoder.cpp
index c6fd45f47..b7fed5304 100644
--- a/src/audio_core/opus/decoder.cpp
+++ b/src/audio_core/opus/decoder.cpp
@@ -148,7 +148,7 @@ Result OpusDecoder::DecodeInterleavedForMultiStream(u32* out_data_size, u64* out
148 auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())}; 148 auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
149 OpusPacketHeader header{ReverseHeader(*header_p)}; 149 OpusPacketHeader header{ReverseHeader(*header_p)};
150 150
151 LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}", 151 LOG_TRACE(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
152 header.size, input_data.size_bytes(), in_data.size_bytes()); 152 header.size, input_data.size_bytes(), in_data.size_bytes());
153 153
154 R_UNLESS(in_data.size_bytes() >= header.size && 154 R_UNLESS(in_data.size_bytes() >= header.size &&
diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp
index bbb598bc5..51a23fe15 100644
--- a/src/audio_core/sink/cubeb_sink.cpp
+++ b/src/audio_core/sink/cubeb_sink.cpp
@@ -146,7 +146,7 @@ public:
146 return; 146 return;
147 } 147 }
148 148
149 paused = true; 149 SignalPause();
150 if (cubeb_stream_stop(stream_backend) != CUBEB_OK) { 150 if (cubeb_stream_stop(stream_backend) != CUBEB_OK) {
151 LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream"); 151 LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream");
152 } 152 }
diff --git a/src/audio_core/sink/sdl2_sink.cpp b/src/audio_core/sink/sdl2_sink.cpp
index 7b89151de..96e0efce2 100644
--- a/src/audio_core/sink/sdl2_sink.cpp
+++ b/src/audio_core/sink/sdl2_sink.cpp
@@ -111,7 +111,7 @@ public:
111 if (device == 0 || paused) { 111 if (device == 0 || paused) {
112 return; 112 return;
113 } 113 }
114 paused = true; 114 SignalPause();
115 SDL_PauseAudioDevice(device, 1); 115 SDL_PauseAudioDevice(device, 1);
116 } 116 }
117 117
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp
index d66d04fae..2a09db599 100644
--- a/src/audio_core/sink/sink_stream.cpp
+++ b/src/audio_core/sink/sink_stream.cpp
@@ -282,11 +282,19 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
282void SinkStream::WaitFreeSpace(std::stop_token stop_token) { 282void SinkStream::WaitFreeSpace(std::stop_token stop_token) {
283 std::unique_lock lk{release_mutex}; 283 std::unique_lock lk{release_mutex};
284 release_cv.wait_for(lk, std::chrono::milliseconds(5), 284 release_cv.wait_for(lk, std::chrono::milliseconds(5),
285 [this]() { return queued_buffers < max_queue_size; }); 285 [this]() { return paused || queued_buffers < max_queue_size; });
286 if (queued_buffers > max_queue_size + 3) { 286 if (queued_buffers > max_queue_size + 3) {
287 Common::CondvarWait(release_cv, lk, stop_token, 287 Common::CondvarWait(release_cv, lk, stop_token,
288 [this] { return queued_buffers < max_queue_size; }); 288 [this] { return paused || queued_buffers < max_queue_size; });
289 } 289 }
290} 290}
291 291
292void SinkStream::SignalPause() {
293 {
294 std::scoped_lock lk{release_mutex};
295 paused = true;
296 }
297 release_cv.notify_one();
298}
299
292} // namespace AudioCore::Sink 300} // namespace AudioCore::Sink
diff --git a/src/audio_core/sink/sink_stream.h b/src/audio_core/sink/sink_stream.h
index 6a4996ca3..f2ccd19b8 100644
--- a/src/audio_core/sink/sink_stream.h
+++ b/src/audio_core/sink/sink_stream.h
@@ -214,6 +214,12 @@ public:
214 void WaitFreeSpace(std::stop_token stop_token); 214 void WaitFreeSpace(std::stop_token stop_token);
215 215
216protected: 216protected:
217 /**
218 * Unblocks the ADSP if the stream is paused.
219 */
220 void SignalPause();
221
222protected:
217 /// Core system 223 /// Core system
218 Core::System& system; 224 Core::System& system;
219 /// Type of this stream 225 /// Type of this stream
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 98b43e49c..51717be06 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -203,6 +203,8 @@ const char* TranslateCategory(Category category) {
203 case Category::Ui: 203 case Category::Ui:
204 case Category::UiGeneral: 204 case Category::UiGeneral:
205 return "UI"; 205 return "UI";
206 case Category::UiAudio:
207 return "UiAudio";
206 case Category::UiLayout: 208 case Category::UiLayout:
207 return "UiLayout"; 209 return "UiLayout";
208 case Category::UiGameList: 210 case Category::UiGameList:
diff --git a/src/common/settings.h b/src/common/settings.h
index 9317075f7..e899f1ae6 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -153,7 +153,7 @@ struct Values {
153 true, 153 true,
154 true}; 154 true};
155 Setting<bool, false> audio_muted{ 155 Setting<bool, false> audio_muted{
156 linkage, false, "audio_muted", Category::Audio, Specialization::Default, false, true}; 156 linkage, false, "audio_muted", Category::Audio, Specialization::Default, true, true};
157 Setting<bool, false> dump_audio_commands{ 157 Setting<bool, false> dump_audio_commands{
158 linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false}; 158 linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
159 159
diff --git a/src/common/settings_common.h b/src/common/settings_common.h
index 1800ab10d..7943223eb 100644
--- a/src/common/settings_common.h
+++ b/src/common/settings_common.h
@@ -32,6 +32,7 @@ enum class Category : u32 {
32 AddOns, 32 AddOns,
33 Controls, 33 Controls,
34 Ui, 34 Ui,
35 UiAudio,
35 UiGeneral, 36 UiGeneral,
36 UiLayout, 37 UiLayout,
37 UiGameList, 38 UiGameList,
diff --git a/src/common/settings_input.cpp b/src/common/settings_input.cpp
index 0a6eea3cf..a6007e7b2 100644
--- a/src/common/settings_input.cpp
+++ b/src/common/settings_input.cpp
@@ -6,10 +6,11 @@
6namespace Settings { 6namespace Settings {
7namespace NativeButton { 7namespace NativeButton {
8const std::array<const char*, NumButtons> mapping = {{ 8const std::array<const char*, NumButtons> mapping = {{
9 "button_a", "button_b", "button_x", "button_y", "button_lstick", 9 "button_a", "button_b", "button_x", "button_y", "button_lstick",
10 "button_rstick", "button_l", "button_r", "button_zl", "button_zr", 10 "button_rstick", "button_l", "button_r", "button_zl", "button_zr",
11 "button_plus", "button_minus", "button_dleft", "button_dup", "button_dright", 11 "button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
12 "button_ddown", "button_sl", "button_sr", "button_home", "button_screenshot", 12 "button_ddown", "button_slleft", "button_srleft", "button_home", "button_screenshot",
13 "button_slright", "button_srright",
13}}; 14}};
14} 15}
15 16
diff --git a/src/common/settings_input.h b/src/common/settings_input.h
index 46f38c703..53a95ef8f 100644
--- a/src/common/settings_input.h
+++ b/src/common/settings_input.h
@@ -29,12 +29,15 @@ enum Values : int {
29 DRight, 29 DRight,
30 DDown, 30 DDown,
31 31
32 SL, 32 SLLeft,
33 SR, 33 SRLeft,
34 34
35 Home, 35 Home,
36 Screenshot, 36 Screenshot,
37 37
38 SLRight,
39 SRRight,
40
38 NumButtons, 41 NumButtons,
39}; 42};
40 43
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8be3bdd08..597890655 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -521,11 +521,21 @@ add_library(core STATIC
521 hle/service/grc/grc.h 521 hle/service/grc/grc.h
522 hle/service/hid/hid.cpp 522 hle/service/hid/hid.cpp
523 hle/service/hid/hid.h 523 hle/service/hid/hid.h
524 hle/service/hid/hid_debug_server.cpp
525 hle/service/hid/hid_debug_server.h
526 hle/service/hid/hid_firmware_settings.cpp
527 hle/service/hid/hid_firmware_settings.h
528 hle/service/hid/hid_server.cpp
529 hle/service/hid/hid_server.h
530 hle/service/hid/hid_system_server.cpp
531 hle/service/hid/hid_system_server.h
524 hle/service/hid/hidbus.cpp 532 hle/service/hid/hidbus.cpp
525 hle/service/hid/hidbus.h 533 hle/service/hid/hidbus.h
526 hle/service/hid/irs.cpp 534 hle/service/hid/irs.cpp
527 hle/service/hid/irs.h 535 hle/service/hid/irs.h
528 hle/service/hid/irs_ring_lifo.h 536 hle/service/hid/irs_ring_lifo.h
537 hle/service/hid/resource_manager.cpp
538 hle/service/hid/resource_manager.h
529 hle/service/hid/ring_lifo.h 539 hle/service/hid/ring_lifo.h
530 hle/service/hid/xcd.cpp 540 hle/service/hid/xcd.cpp
531 hle/service/hid/xcd.h 541 hle/service/hid/xcd.h
@@ -715,6 +725,7 @@ add_library(core STATIC
715 hle/service/nvnflinger/producer_listener.h 725 hle/service/nvnflinger/producer_listener.h
716 hle/service/nvnflinger/status.h 726 hle/service/nvnflinger/status.h
717 hle/service/nvnflinger/ui/fence.h 727 hle/service/nvnflinger/ui/fence.h
728 hle/service/nvnflinger/ui/graphic_buffer.cpp
718 hle/service/nvnflinger/ui/graphic_buffer.h 729 hle/service/nvnflinger/ui/graphic_buffer.h
719 hle/service/nvnflinger/window.h 730 hle/service/nvnflinger/window.h
720 hle/service/olsc/olsc.cpp 731 hle/service/olsc/olsc.cpp
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 5e27dde58..558fba5bd 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -153,6 +153,14 @@ void ARM_Interface::Run() {
153 Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())}; 153 Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())};
154 HaltReason hr{}; 154 HaltReason hr{};
155 155
156 // If the thread is scheduled for termination, exit the thread.
157 if (current_thread->HasDpc()) {
158 if (current_thread->IsTerminationRequested()) {
159 current_thread->Exit();
160 UNREACHABLE();
161 }
162 }
163
156 // Notify the debugger and go to sleep if a step was performed 164 // Notify the debugger and go to sleep if a step was performed
157 // and this thread has been scheduled again. 165 // and this thread has been scheduled again.
158 if (current_thread->GetStepState() == StepState::StepPerformed) { 166 if (current_thread->GetStepState() == StepState::StepPerformed) {
@@ -174,14 +182,6 @@ void ARM_Interface::Run() {
174 } 182 }
175 system.ExitCPUProfile(); 183 system.ExitCPUProfile();
176 184
177 // If the thread is scheduled for termination, exit the thread.
178 if (current_thread->HasDpc()) {
179 if (current_thread->IsTerminationRequested()) {
180 current_thread->Exit();
181 UNREACHABLE();
182 }
183 }
184
185 // Notify the debugger and go to sleep if a breakpoint was hit, 185 // Notify the debugger and go to sleep if a breakpoint was hit,
186 // or if the thread is unable to continue for any reason. 186 // or if the thread is unable to continue for any reason.
187 if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) { 187 if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index e671b270f..d6b5abc68 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -76,6 +76,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
76} 76}
77 77
78void CoreTiming::ClearPendingEvents() { 78void CoreTiming::ClearPendingEvents() {
79 std::scoped_lock lock{basic_lock};
79 event_queue.clear(); 80 event_queue.clear();
80} 81}
81 82
@@ -113,6 +114,7 @@ bool CoreTiming::IsRunning() const {
113} 114}
114 115
115bool CoreTiming::HasPendingEvents() const { 116bool CoreTiming::HasPendingEvents() const {
117 std::scoped_lock lock{basic_lock};
116 return !(wait_set && event_queue.empty()); 118 return !(wait_set && event_queue.empty());
117} 119}
118 120
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 26a8b93a7..21548f0a9 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -161,7 +161,7 @@ private:
161 std::shared_ptr<EventType> ev_lost; 161 std::shared_ptr<EventType> ev_lost;
162 Common::Event event{}; 162 Common::Event event{};
163 Common::Event pause_event{}; 163 Common::Event pause_event{};
164 std::mutex basic_lock; 164 mutable std::mutex basic_lock;
165 std::mutex advance_lock; 165 std::mutex advance_lock;
166 std::unique_ptr<std::jthread> timer_thread; 166 std::unique_ptr<std::jthread> timer_thread;
167 std::atomic<bool> paused{}; 167 std::atomic<bool> paused{};
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
index 79114bb6d..fae15a556 100644
--- a/src/core/hid/emulated_console.h
+++ b/src/core/hid/emulated_console.h
@@ -38,14 +38,6 @@ using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
38using ConsoleMotionValues = ConsoleMotionInfo; 38using ConsoleMotionValues = ConsoleMotionInfo;
39using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>; 39using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
40 40
41struct TouchFinger {
42 u64 last_touch{};
43 Common::Point<float> position{};
44 u32 id{};
45 TouchAttribute attribute{};
46 bool pressed{};
47};
48
49// Contains all motion related data that is used on the services 41// Contains all motion related data that is used on the services
50struct ConsoleMotion { 42struct ConsoleMotion {
51 Common::Vec3f accel{}; 43 Common::Vec3f accel{};
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index b08a71446..34927cddd 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -243,10 +243,12 @@ void EmulatedController::LoadTASParams() {
243 tas_button_params[Settings::NativeButton::DUp].Set("button", 13); 243 tas_button_params[Settings::NativeButton::DUp].Set("button", 13);
244 tas_button_params[Settings::NativeButton::DRight].Set("button", 14); 244 tas_button_params[Settings::NativeButton::DRight].Set("button", 14);
245 tas_button_params[Settings::NativeButton::DDown].Set("button", 15); 245 tas_button_params[Settings::NativeButton::DDown].Set("button", 15);
246 tas_button_params[Settings::NativeButton::SL].Set("button", 16); 246 tas_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
247 tas_button_params[Settings::NativeButton::SR].Set("button", 17); 247 tas_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
248 tas_button_params[Settings::NativeButton::Home].Set("button", 18); 248 tas_button_params[Settings::NativeButton::Home].Set("button", 18);
249 tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19); 249 tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
250 tas_button_params[Settings::NativeButton::SLRight].Set("button", 20);
251 tas_button_params[Settings::NativeButton::SRRight].Set("button", 21);
250 252
251 tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0); 253 tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
252 tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); 254 tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
@@ -296,10 +298,12 @@ void EmulatedController::LoadVirtualGamepadParams() {
296 virtual_button_params[Settings::NativeButton::DUp].Set("button", 13); 298 virtual_button_params[Settings::NativeButton::DUp].Set("button", 13);
297 virtual_button_params[Settings::NativeButton::DRight].Set("button", 14); 299 virtual_button_params[Settings::NativeButton::DRight].Set("button", 14);
298 virtual_button_params[Settings::NativeButton::DDown].Set("button", 15); 300 virtual_button_params[Settings::NativeButton::DDown].Set("button", 15);
299 virtual_button_params[Settings::NativeButton::SL].Set("button", 16); 301 virtual_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
300 virtual_button_params[Settings::NativeButton::SR].Set("button", 17); 302 virtual_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
301 virtual_button_params[Settings::NativeButton::Home].Set("button", 18); 303 virtual_button_params[Settings::NativeButton::Home].Set("button", 18);
302 virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19); 304 virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
305 virtual_button_params[Settings::NativeButton::SLRight].Set("button", 20);
306 virtual_button_params[Settings::NativeButton::SRRight].Set("button", 21);
303 307
304 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0); 308 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
305 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); 309 virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
@@ -867,12 +871,16 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
867 controller.npad_button_state.down.Assign(current_status.value); 871 controller.npad_button_state.down.Assign(current_status.value);
868 controller.debug_pad_button_state.d_down.Assign(current_status.value); 872 controller.debug_pad_button_state.d_down.Assign(current_status.value);
869 break; 873 break;
870 case Settings::NativeButton::SL: 874 case Settings::NativeButton::SLLeft:
871 controller.npad_button_state.left_sl.Assign(current_status.value); 875 controller.npad_button_state.left_sl.Assign(current_status.value);
876 break;
877 case Settings::NativeButton::SLRight:
872 controller.npad_button_state.right_sl.Assign(current_status.value); 878 controller.npad_button_state.right_sl.Assign(current_status.value);
873 break; 879 break;
874 case Settings::NativeButton::SR: 880 case Settings::NativeButton::SRLeft:
875 controller.npad_button_state.left_sr.Assign(current_status.value); 881 controller.npad_button_state.left_sr.Assign(current_status.value);
882 break;
883 case Settings::NativeButton::SRRight:
876 controller.npad_button_state.right_sr.Assign(current_status.value); 884 controller.npad_button_state.right_sr.Assign(current_status.value);
877 break; 885 break;
878 case Settings::NativeButton::Home: 886 case Settings::NativeButton::Home:
@@ -1890,12 +1898,16 @@ NpadButton EmulatedController::GetTurboButtonMask() const {
1890 case Settings::NativeButton::DDown: 1898 case Settings::NativeButton::DDown:
1891 button_mask.down.Assign(1); 1899 button_mask.down.Assign(1);
1892 break; 1900 break;
1893 case Settings::NativeButton::SL: 1901 case Settings::NativeButton::SLLeft:
1894 button_mask.left_sl.Assign(1); 1902 button_mask.left_sl.Assign(1);
1903 break;
1904 case Settings::NativeButton::SLRight:
1895 button_mask.right_sl.Assign(1); 1905 button_mask.right_sl.Assign(1);
1896 break; 1906 break;
1897 case Settings::NativeButton::SR: 1907 case Settings::NativeButton::SRLeft:
1898 button_mask.left_sr.Assign(1); 1908 button_mask.left_sr.Assign(1);
1909 break;
1910 case Settings::NativeButton::SRRight:
1899 button_mask.right_sr.Assign(1); 1911 button_mask.right_sr.Assign(1);
1900 break; 1912 break;
1901 default: 1913 default:
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 7ba75a50c..9d48cd90e 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -356,6 +356,14 @@ struct TouchState {
356}; 356};
357static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); 357static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
358 358
359struct TouchFinger {
360 u64 last_touch{};
361 Common::Point<float> position{};
362 u32 id{};
363 TouchAttribute attribute{};
364 bool pressed{};
365};
366
359// This is nn::hid::TouchScreenConfigurationForNx 367// This is nn::hid::TouchScreenConfigurationForNx
360struct TouchScreenConfigurationForNx { 368struct TouchScreenConfigurationForNx {
361 TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting}; 369 TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting};
diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp
index 76d6b8ab0..11359f318 100644
--- a/src/core/hid/input_interpreter.cpp
+++ b/src/core/hid/input_interpreter.cpp
@@ -5,13 +5,14 @@
5#include "core/hid/hid_types.h" 5#include "core/hid/hid_types.h"
6#include "core/hid/input_interpreter.h" 6#include "core/hid/input_interpreter.h"
7#include "core/hle/service/hid/controllers/npad.h" 7#include "core/hle/service/hid/controllers/npad.h"
8#include "core/hle/service/hid/hid.h" 8#include "core/hle/service/hid/hid_server.h"
9#include "core/hle/service/hid/resource_manager.h"
9#include "core/hle/service/sm/sm.h" 10#include "core/hle/service/sm/sm.h"
10 11
11InputInterpreter::InputInterpreter(Core::System& system) 12InputInterpreter::InputInterpreter(Core::System& system)
12 : npad{system.ServiceManager() 13 : npad{system.ServiceManager()
13 .GetService<Service::HID::Hid>("hid") 14 .GetService<Service::HID::IHidServer>("hid")
14 ->GetAppletResource() 15 ->GetResourceManager()
15 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} { 16 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
16 ResetButtonStates(); 17 ResetButtonStates();
17} 18}
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp
index 6a57ad55c..47dc8fd35 100644
--- a/src/core/hle/kernel/k_page_table_base.cpp
+++ b/src/core/hle/kernel/k_page_table_base.cpp
@@ -1617,9 +1617,9 @@ void KPageTableBase::RemapPageGroup(PageLinkedList* page_list, KProcessAddress a
1617 const KMemoryInfo info = it->GetMemoryInfo(); 1617 const KMemoryInfo info = it->GetMemoryInfo();
1618 1618
1619 // Determine the range to map. 1619 // Determine the range to map.
1620 KProcessAddress map_address = std::max(info.GetAddress(), GetInteger(start_address)); 1620 KProcessAddress map_address = std::max<u64>(info.GetAddress(), GetInteger(start_address));
1621 const KProcessAddress map_end_address = 1621 const KProcessAddress map_end_address =
1622 std::min(info.GetEndAddress(), GetInteger(end_address)); 1622 std::min<u64>(info.GetEndAddress(), GetInteger(end_address));
1623 ASSERT(map_end_address != map_address); 1623 ASSERT(map_end_address != map_address);
1624 1624
1625 // Determine if we should disable head merge. 1625 // Determine if we should disable head merge.
diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp
index c58d67d7d..0bcd87062 100644
--- a/src/core/hle/service/hid/controllers/controller_base.cpp
+++ b/src/core/hle/service/hid/controllers/controller_base.cpp
@@ -8,12 +8,17 @@ namespace Service::HID {
8ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {} 8ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
9ControllerBase::~ControllerBase() = default; 9ControllerBase::~ControllerBase() = default;
10 10
11void ControllerBase::ActivateController() { 11Result ControllerBase::Activate() {
12 if (is_activated) { 12 if (is_activated) {
13 return; 13 return ResultSuccess;
14 } 14 }
15 is_activated = true; 15 is_activated = true;
16 OnInit(); 16 OnInit();
17 return ResultSuccess;
18}
19
20Result ControllerBase::Activate(u64 aruid) {
21 return Activate();
17} 22}
18 23
19void ControllerBase::DeactivateController() { 24void ControllerBase::DeactivateController() {
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index d6f7a5073..9a44ee41e 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/hle/result.h"
7 8
8namespace Core::Timing { 9namespace Core::Timing {
9class CoreTiming; 10class CoreTiming;
@@ -31,7 +32,8 @@ public:
31 // When the controller is requesting a motion update for the shared memory 32 // When the controller is requesting a motion update for the shared memory
32 virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {} 33 virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
33 34
34 void ActivateController(); 35 Result Activate();
36 Result Activate(u64 aruid);
35 37
36 void DeactivateController(); 38 void DeactivateController();
37 39
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 21695bda2..d46bf917e 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -457,12 +457,14 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
457 pad_entry.l_stick = stick_state.left; 457 pad_entry.l_stick = stick_state.left;
458 } 458 }
459 459
460 if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) { 460 if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft ||
461 controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
461 pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl); 462 pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl);
462 pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr); 463 pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr);
463 } 464 }
464 465
465 if (controller_type == Core::HID::NpadStyleIndex::JoyconRight) { 466 if (controller_type == Core::HID::NpadStyleIndex::JoyconRight ||
467 controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
466 pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl); 468 pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl);
467 pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr); 469 pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr);
468 } 470 }
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 949e58a4c..e23b4986c 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -86,6 +86,13 @@ public:
86 Default = 3, 86 Default = 3,
87 }; 87 };
88 88
89 enum class NpadRevision : u32 {
90 Revision0 = 0,
91 Revision1 = 1,
92 Revision2 = 2,
93 Revision3 = 3,
94 };
95
89 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); 96 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
90 Core::HID::NpadStyleTag GetSupportedStyleSet() const; 97 Core::HID::NpadStyleTag GetSupportedStyleSet() const;
91 98
diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp
index 73a2a2b91..51a18335f 100644
--- a/src/core/hle/service/hid/controllers/palma.cpp
+++ b/src/core/hle/service/hid/controllers/palma.cpp
@@ -44,7 +44,7 @@ Result Controller_Palma::InitializePalma(const PalmaConnectionHandle& handle) {
44 if (handle.npad_id != active_handle.npad_id) { 44 if (handle.npad_id != active_handle.npad_id) {
45 return InvalidPalmaHandle; 45 return InvalidPalmaHandle;
46 } 46 }
47 ActivateController(); 47 Activate();
48 return ResultSuccess; 48 return ResultSuccess;
49} 49}
50 50
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1d4101be9..1b7381d8d 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1,2862 +1,39 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <array>
5#include "common/common_types.h"
6#include "common/logging/log.h"
7#include "common/settings.h"
8#include "core/core.h"
9#include "core/core_timing.h"
10#include "core/hid/hid_core.h"
11#include "core/hle/kernel/k_readable_event.h"
12#include "core/hle/kernel/k_shared_memory.h"
13#include "core/hle/kernel/k_transfer_memory.h"
14#include "core/hle/kernel/kernel.h"
15#include "core/hle/service/hid/errors.h"
16#include "core/hle/service/hid/hid.h" 4#include "core/hle/service/hid/hid.h"
5#include "core/hle/service/hid/hid_debug_server.h"
6#include "core/hle/service/hid/hid_firmware_settings.h"
7#include "core/hle/service/hid/hid_server.h"
8#include "core/hle/service/hid/hid_system_server.h"
17#include "core/hle/service/hid/hidbus.h" 9#include "core/hle/service/hid/hidbus.h"
18#include "core/hle/service/hid/irs.h" 10#include "core/hle/service/hid/irs.h"
11#include "core/hle/service/hid/resource_manager.h"
19#include "core/hle/service/hid/xcd.h" 12#include "core/hle/service/hid/xcd.h"
20#include "core/hle/service/ipc_helpers.h"
21#include "core/hle/service/server_manager.h" 13#include "core/hle/service/server_manager.h"
22#include "core/memory.h"
23
24#include "core/hle/service/hid/controllers/console_sixaxis.h"
25#include "core/hle/service/hid/controllers/controller_base.h"
26#include "core/hle/service/hid/controllers/debug_pad.h"
27#include "core/hle/service/hid/controllers/gesture.h"
28#include "core/hle/service/hid/controllers/keyboard.h"
29#include "core/hle/service/hid/controllers/mouse.h"
30#include "core/hle/service/hid/controllers/npad.h"
31#include "core/hle/service/hid/controllers/palma.h"
32#include "core/hle/service/hid/controllers/stubbed.h"
33#include "core/hle/service/hid/controllers/touchscreen.h"
34#include "core/hle/service/hid/controllers/xpad.h"
35 14
36namespace Service::HID { 15namespace Service::HID {
37 16
38// Updating period for each HID device.
39// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
40// Correct npad_update_ns is 4ms this is overclocked to lower input lag
41constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
42constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
43constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
44constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
45
46IAppletResource::IAppletResource(Core::System& system_,
47 KernelHelpers::ServiceContext& service_context_)
48 : ServiceFramework{system_, "IAppletResource"}, service_context{service_context_} {
49 static const FunctionInfo functions[] = {
50 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
51 };
52 RegisterHandlers(functions);
53 u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
54 MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
55 MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
56 MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
57 MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
58 MakeController<Controller_XPad>(HidController::XPad, shared_memory);
59 MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
60 MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
61 MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
62 MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
63 MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
64 MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
65 MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
66 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
67 MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory);
68 MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
69
70 // Homebrew doesn't try to activate some controllers, so we activate them by default
71 GetController<Controller_NPad>(HidController::NPad).ActivateController();
72 GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
73
74 GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
75 GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
76 GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
77 GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
78 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
79 GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00);
80
81 // Register update callbacks
82 npad_update_event = Core::Timing::CreateEvent(
83 "HID::UpdatePadCallback",
84 [this](std::uintptr_t user_data, s64 time,
85 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
86 const auto guard = LockService();
87 UpdateNpad(user_data, ns_late);
88 return std::nullopt;
89 });
90 default_update_event = Core::Timing::CreateEvent(
91 "HID::UpdateDefaultCallback",
92 [this](std::uintptr_t user_data, s64 time,
93 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
94 const auto guard = LockService();
95 UpdateControllers(user_data, ns_late);
96 return std::nullopt;
97 });
98 mouse_keyboard_update_event = Core::Timing::CreateEvent(
99 "HID::UpdateMouseKeyboardCallback",
100 [this](std::uintptr_t user_data, s64 time,
101 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
102 const auto guard = LockService();
103 UpdateMouseKeyboard(user_data, ns_late);
104 return std::nullopt;
105 });
106 motion_update_event = Core::Timing::CreateEvent(
107 "HID::UpdateMotionCallback",
108 [this](std::uintptr_t user_data, s64 time,
109 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
110 const auto guard = LockService();
111 UpdateMotion(user_data, ns_late);
112 return std::nullopt;
113 });
114
115 system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
116 system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
117 default_update_event);
118 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
119 mouse_keyboard_update_event);
120 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
121 motion_update_event);
122
123 system.HIDCore().ReloadInputDevices();
124}
125
126void IAppletResource::ActivateController(HidController controller) {
127 controllers[static_cast<size_t>(controller)]->ActivateController();
128}
129
130void IAppletResource::DeactivateController(HidController controller) {
131 controllers[static_cast<size_t>(controller)]->DeactivateController();
132}
133
134IAppletResource::~IAppletResource() {
135 system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
136 system.CoreTiming().UnscheduleEvent(default_update_event, 0);
137 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
138 system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
139}
140
141void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
142 LOG_DEBUG(Service_HID, "called");
143
144 IPC::ResponseBuilder rb{ctx, 2, 1};
145 rb.Push(ResultSuccess);
146 rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
147}
148
149void IAppletResource::UpdateControllers(std::uintptr_t user_data,
150 std::chrono::nanoseconds ns_late) {
151 auto& core_timing = system.CoreTiming();
152
153 for (const auto& controller : controllers) {
154 // Keyboard has it's own update event
155 if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
156 continue;
157 }
158 // Mouse has it's own update event
159 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
160 continue;
161 }
162 // Npad has it's own update event
163 if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
164 continue;
165 }
166 controller->OnUpdate(core_timing);
167 }
168}
169
170void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
171 auto& core_timing = system.CoreTiming();
172
173 controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
174}
175
176void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
177 std::chrono::nanoseconds ns_late) {
178 auto& core_timing = system.CoreTiming();
179
180 controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
181 controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
182}
183
184void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
185 auto& core_timing = system.CoreTiming();
186
187 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
188}
189
190class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
191public:
192 explicit IActiveVibrationDeviceList(Core::System& system_,
193 std::shared_ptr<IAppletResource> applet_resource_)
194 : ServiceFramework{system_, "IActiveVibrationDeviceList"},
195 applet_resource(applet_resource_) {
196 // clang-format off
197 static const FunctionInfo functions[] = {
198 {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
199 };
200 // clang-format on
201
202 RegisterHandlers(functions);
203 }
204
205private:
206 void InitializeVibrationDevice(HLERequestContext& ctx) {
207 IPC::RequestParser rp{ctx};
208 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
209
210 if (applet_resource != nullptr) {
211 applet_resource->GetController<Controller_NPad>(HidController::NPad)
212 .InitializeVibrationDevice(vibration_device_handle);
213 }
214
215 LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
216 vibration_device_handle.npad_type, vibration_device_handle.npad_id,
217 vibration_device_handle.device_index);
218
219 IPC::ResponseBuilder rb{ctx, 2};
220 rb.Push(ResultSuccess);
221 }
222
223 std::shared_ptr<IAppletResource> applet_resource;
224};
225
226std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
227 if (applet_resource == nullptr) {
228 applet_resource = std::make_shared<IAppletResource>(system, service_context);
229 }
230
231 return applet_resource;
232}
233
234Hid::Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_)
235 : ServiceFramework{system_, "hid"}, applet_resource{applet_resource_}, service_context{
236 system_,
237 service_name} {
238 // clang-format off
239 static const FunctionInfo functions[] = {
240 {0, &Hid::CreateAppletResource, "CreateAppletResource"},
241 {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
242 {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
243 {21, &Hid::ActivateMouse, "ActivateMouse"},
244 {26, nullptr, "ActivateDebugMouse"},
245 {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
246 {32, &Hid::SendKeyboardLockKeyEvent, "SendKeyboardLockKeyEvent"},
247 {40, nullptr, "AcquireXpadIdEventHandle"},
248 {41, nullptr, "ReleaseXpadIdEventHandle"},
249 {51, &Hid::ActivateXpad, "ActivateXpad"},
250 {55, &Hid::GetXpadIDs, "GetXpadIds"},
251 {56, nullptr, "ActivateJoyXpad"},
252 {58, nullptr, "GetJoyXpadLifoHandle"},
253 {59, nullptr, "GetJoyXpadIds"},
254 {60, &Hid::ActivateSixAxisSensor, "ActivateSixAxisSensor"},
255 {61, &Hid::DeactivateSixAxisSensor, "DeactivateSixAxisSensor"},
256 {62, nullptr, "GetSixAxisSensorLifoHandle"},
257 {63, nullptr, "ActivateJoySixAxisSensor"},
258 {64, nullptr, "DeactivateJoySixAxisSensor"},
259 {65, nullptr, "GetJoySixAxisSensorLifoHandle"},
260 {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
261 {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
262 {68, &Hid::IsSixAxisSensorFusionEnabled, "IsSixAxisSensorFusionEnabled"},
263 {69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"},
264 {70, &Hid::SetSixAxisSensorFusionParameters, "SetSixAxisSensorFusionParameters"},
265 {71, &Hid::GetSixAxisSensorFusionParameters, "GetSixAxisSensorFusionParameters"},
266 {72, &Hid::ResetSixAxisSensorFusionParameters, "ResetSixAxisSensorFusionParameters"},
267 {73, nullptr, "SetAccelerometerParameters"},
268 {74, nullptr, "GetAccelerometerParameters"},
269 {75, nullptr, "ResetAccelerometerParameters"},
270 {76, nullptr, "SetAccelerometerPlayMode"},
271 {77, nullptr, "GetAccelerometerPlayMode"},
272 {78, nullptr, "ResetAccelerometerPlayMode"},
273 {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
274 {80, &Hid::GetGyroscopeZeroDriftMode, "GetGyroscopeZeroDriftMode"},
275 {81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"},
276 {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
277 {83, &Hid::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"},
278 {84, &Hid::EnableSixAxisSensorUnalteredPassthrough, "EnableSixAxisSensorUnalteredPassthrough"},
279 {85, &Hid::IsSixAxisSensorUnalteredPassthroughEnabled, "IsSixAxisSensorUnalteredPassthroughEnabled"},
280 {86, nullptr, "StoreSixAxisSensorCalibrationParameter"},
281 {87, &Hid::LoadSixAxisSensorCalibrationParameter, "LoadSixAxisSensorCalibrationParameter"},
282 {88, &Hid::GetSixAxisSensorIcInformation, "GetSixAxisSensorIcInformation"},
283 {89, &Hid::ResetIsSixAxisSensorDeviceNewlyAssigned, "ResetIsSixAxisSensorDeviceNewlyAssigned"},
284 {91, &Hid::ActivateGesture, "ActivateGesture"},
285 {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
286 {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
287 {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
288 {103, &Hid::ActivateNpad, "ActivateNpad"},
289 {104, &Hid::DeactivateNpad, "DeactivateNpad"},
290 {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
291 {107, &Hid::DisconnectNpad, "DisconnectNpad"},
292 {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
293 {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
294 {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
295 {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
296 {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
297 {123, &Hid::SetNpadJoyAssignmentModeSingle, "SetNpadJoyAssignmentModeSingle"},
298 {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
299 {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
300 {126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"},
301 {127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"},
302 {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
303 {129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"},
304 {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
305 {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
306 {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
307 {133, &Hid::SetNpadJoyAssignmentModeSingleWithDestination, "SetNpadJoyAssignmentModeSingleWithDestination"},
308 {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
309 {135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"},
310 {136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"},
311 {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
312 {201, &Hid::SendVibrationValue, "SendVibrationValue"},
313 {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
314 {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
315 {204, &Hid::PermitVibration, "PermitVibration"},
316 {205, &Hid::IsVibrationPermitted, "IsVibrationPermitted"},
317 {206, &Hid::SendVibrationValues, "SendVibrationValues"},
318 {207, &Hid::SendVibrationGcErmCommand, "SendVibrationGcErmCommand"},
319 {208, &Hid::GetActualVibrationGcErmCommand, "GetActualVibrationGcErmCommand"},
320 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
321 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
322 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
323 {212, nullptr, "SendVibrationValueInBool"},
324 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
325 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
326 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
327 {303, &Hid::ActivateSevenSixAxisSensor, "ActivateSevenSixAxisSensor"},
328 {304, &Hid::StartSevenSixAxisSensor, "StartSevenSixAxisSensor"},
329 {305, &Hid::StopSevenSixAxisSensor, "StopSevenSixAxisSensor"},
330 {306, &Hid::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"},
331 {307, &Hid::FinalizeSevenSixAxisSensor, "FinalizeSevenSixAxisSensor"},
332 {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
333 {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
334 {310, &Hid::ResetSevenSixAxisSensorTimestamp, "ResetSevenSixAxisSensorTimestamp"},
335 {400, &Hid::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
336 {401, nullptr, "EnableUsbFullKeyController"},
337 {402, nullptr, "IsUsbFullKeyControllerConnected"},
338 {403, nullptr, "HasBattery"},
339 {404, nullptr, "HasLeftRightBattery"},
340 {405, nullptr, "GetNpadInterfaceType"},
341 {406, nullptr, "GetNpadLeftRightInterfaceType"},
342 {407, nullptr, "GetNpadOfHighestBatteryLevel"},
343 {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
344 {500, &Hid::GetPalmaConnectionHandle, "GetPalmaConnectionHandle"},
345 {501, &Hid::InitializePalma, "InitializePalma"},
346 {502, &Hid::AcquirePalmaOperationCompleteEvent, "AcquirePalmaOperationCompleteEvent"},
347 {503, &Hid::GetPalmaOperationInfo, "GetPalmaOperationInfo"},
348 {504, &Hid::PlayPalmaActivity, "PlayPalmaActivity"},
349 {505, &Hid::SetPalmaFrModeType, "SetPalmaFrModeType"},
350 {506, &Hid::ReadPalmaStep, "ReadPalmaStep"},
351 {507, &Hid::EnablePalmaStep, "EnablePalmaStep"},
352 {508, &Hid::ResetPalmaStep, "ResetPalmaStep"},
353 {509, &Hid::ReadPalmaApplicationSection, "ReadPalmaApplicationSection"},
354 {510, &Hid::WritePalmaApplicationSection, "WritePalmaApplicationSection"},
355 {511, &Hid::ReadPalmaUniqueCode, "ReadPalmaUniqueCode"},
356 {512, &Hid::SetPalmaUniqueCodeInvalid, "SetPalmaUniqueCodeInvalid"},
357 {513, &Hid::WritePalmaActivityEntry, "WritePalmaActivityEntry"},
358 {514, &Hid::WritePalmaRgbLedPatternEntry, "WritePalmaRgbLedPatternEntry"},
359 {515, &Hid::WritePalmaWaveEntry, "WritePalmaWaveEntry"},
360 {516, &Hid::SetPalmaDataBaseIdentificationVersion, "SetPalmaDataBaseIdentificationVersion"},
361 {517, &Hid::GetPalmaDataBaseIdentificationVersion, "GetPalmaDataBaseIdentificationVersion"},
362 {518, &Hid::SuspendPalmaFeature, "SuspendPalmaFeature"},
363 {519, &Hid::GetPalmaOperationResult, "GetPalmaOperationResult"},
364 {520, &Hid::ReadPalmaPlayLog, "ReadPalmaPlayLog"},
365 {521, &Hid::ResetPalmaPlayLog, "ResetPalmaPlayLog"},
366 {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
367 {523, &Hid::SetIsPalmaPairedConnectable, "SetIsPalmaPairedConnectable"},
368 {524, &Hid::PairPalma, "PairPalma"},
369 {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
370 {526, &Hid::CancelWritePalmaWaveEntry, "CancelWritePalmaWaveEntry"},
371 {527, &Hid::EnablePalmaBoostMode, "EnablePalmaBoostMode"},
372 {528, &Hid::GetPalmaBluetoothAddress, "GetPalmaBluetoothAddress"},
373 {529, &Hid::SetDisallowedPalmaConnection, "SetDisallowedPalmaConnection"},
374 {1000, &Hid::SetNpadCommunicationMode, "SetNpadCommunicationMode"},
375 {1001, &Hid::GetNpadCommunicationMode, "GetNpadCommunicationMode"},
376 {1002, &Hid::SetTouchScreenConfiguration, "SetTouchScreenConfiguration"},
377 {1003, &Hid::IsFirmwareUpdateNeededForNotification, "IsFirmwareUpdateNeededForNotification"},
378 {2000, nullptr, "ActivateDigitizer"},
379 };
380 // clang-format on
381
382 RegisterHandlers(functions);
383}
384
385Hid::~Hid() = default;
386
387void Hid::CreateAppletResource(HLERequestContext& ctx) {
388 IPC::RequestParser rp{ctx};
389 const auto applet_resource_user_id{rp.Pop<u64>()};
390
391 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
392
393 if (applet_resource == nullptr) {
394 applet_resource = std::make_shared<IAppletResource>(system, service_context);
395 }
396
397 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
398 rb.Push(ResultSuccess);
399 rb.PushIpcInterface<IAppletResource>(applet_resource);
400}
401
402void Hid::ActivateDebugPad(HLERequestContext& ctx) {
403 IPC::RequestParser rp{ctx};
404 const auto applet_resource_user_id{rp.Pop<u64>()};
405
406 applet_resource->ActivateController(HidController::DebugPad);
407
408 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
409
410 IPC::ResponseBuilder rb{ctx, 2};
411 rb.Push(ResultSuccess);
412}
413
414void Hid::ActivateTouchScreen(HLERequestContext& ctx) {
415 IPC::RequestParser rp{ctx};
416 const auto applet_resource_user_id{rp.Pop<u64>()};
417
418 applet_resource->ActivateController(HidController::Touchscreen);
419
420 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
421
422 IPC::ResponseBuilder rb{ctx, 2};
423 rb.Push(ResultSuccess);
424}
425
426void Hid::ActivateMouse(HLERequestContext& ctx) {
427 IPC::RequestParser rp{ctx};
428 const auto applet_resource_user_id{rp.Pop<u64>()};
429
430 applet_resource->ActivateController(HidController::Mouse);
431
432 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
433
434 IPC::ResponseBuilder rb{ctx, 2};
435 rb.Push(ResultSuccess);
436}
437
438void Hid::ActivateKeyboard(HLERequestContext& ctx) {
439 IPC::RequestParser rp{ctx};
440 const auto applet_resource_user_id{rp.Pop<u64>()};
441
442 applet_resource->ActivateController(HidController::Keyboard);
443
444 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
445
446 IPC::ResponseBuilder rb{ctx, 2};
447 rb.Push(ResultSuccess);
448}
449
450void Hid::SendKeyboardLockKeyEvent(HLERequestContext& ctx) {
451 IPC::RequestParser rp{ctx};
452 const auto flags{rp.Pop<u32>()};
453
454 LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
455
456 IPC::ResponseBuilder rb{ctx, 2};
457 rb.Push(ResultSuccess);
458}
459
460void Hid::ActivateXpad(HLERequestContext& ctx) {
461 IPC::RequestParser rp{ctx};
462 struct Parameters {
463 u32 basic_xpad_id;
464 INSERT_PADDING_WORDS_NOINIT(1);
465 u64 applet_resource_user_id;
466 };
467 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
468
469 const auto parameters{rp.PopRaw<Parameters>()};
470
471 applet_resource->ActivateController(HidController::XPad);
472
473 LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
474 parameters.basic_xpad_id, parameters.applet_resource_user_id);
475
476 IPC::ResponseBuilder rb{ctx, 2};
477 rb.Push(ResultSuccess);
478}
479
480void Hid::GetXpadIDs(HLERequestContext& ctx) {
481 IPC::RequestParser rp{ctx};
482 const auto applet_resource_user_id{rp.Pop<u64>()};
483
484 LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id);
485
486 IPC::ResponseBuilder rb{ctx, 3};
487 rb.Push(ResultSuccess);
488 rb.Push(0);
489}
490
491void Hid::ActivateSixAxisSensor(HLERequestContext& ctx) {
492 IPC::RequestParser rp{ctx};
493 struct Parameters {
494 u32 basic_xpad_id;
495 INSERT_PADDING_WORDS_NOINIT(1);
496 u64 applet_resource_user_id;
497 };
498 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
499
500 const auto parameters{rp.PopRaw<Parameters>()};
501
502 // This function does nothing on 10.0.0+
503
504 LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}",
505 parameters.basic_xpad_id, parameters.applet_resource_user_id);
506
507 IPC::ResponseBuilder rb{ctx, 2};
508 rb.Push(ResultSuccess);
509}
510
511void Hid::DeactivateSixAxisSensor(HLERequestContext& ctx) {
512 IPC::RequestParser rp{ctx};
513 struct Parameters {
514 u32 basic_xpad_id;
515 INSERT_PADDING_WORDS_NOINIT(1);
516 u64 applet_resource_user_id;
517 };
518 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
519
520 const auto parameters{rp.PopRaw<Parameters>()};
521
522 // This function does nothing on 10.0.0+
523
524 LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}",
525 parameters.basic_xpad_id, parameters.applet_resource_user_id);
526
527 IPC::ResponseBuilder rb{ctx, 2};
528 rb.Push(ResultSuccess);
529}
530
531void Hid::StartSixAxisSensor(HLERequestContext& ctx) {
532 IPC::RequestParser rp{ctx};
533 struct Parameters {
534 Core::HID::SixAxisSensorHandle sixaxis_handle;
535 INSERT_PADDING_WORDS_NOINIT(1);
536 u64 applet_resource_user_id;
537 };
538 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
539
540 const auto parameters{rp.PopRaw<Parameters>()};
541
542 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
543 const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, true);
544
545 LOG_DEBUG(Service_HID,
546 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
547 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
548 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
549
550 IPC::ResponseBuilder rb{ctx, 2};
551 rb.Push(result);
552}
553
554void Hid::StopSixAxisSensor(HLERequestContext& ctx) {
555 IPC::RequestParser rp{ctx};
556 struct Parameters {
557 Core::HID::SixAxisSensorHandle sixaxis_handle;
558 INSERT_PADDING_WORDS_NOINIT(1);
559 u64 applet_resource_user_id;
560 };
561 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
562
563 const auto parameters{rp.PopRaw<Parameters>()};
564
565 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
566 const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, false);
567
568 LOG_DEBUG(Service_HID,
569 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
570 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
571 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
572
573 IPC::ResponseBuilder rb{ctx, 2};
574 rb.Push(result);
575}
576
577void Hid::IsSixAxisSensorFusionEnabled(HLERequestContext& ctx) {
578 IPC::RequestParser rp{ctx};
579 struct Parameters {
580 Core::HID::SixAxisSensorHandle sixaxis_handle;
581 INSERT_PADDING_WORDS_NOINIT(1);
582 u64 applet_resource_user_id;
583 };
584 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
585
586 const auto parameters{rp.PopRaw<Parameters>()};
587
588 bool is_enabled{};
589 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
590 const auto result =
591 controller.IsSixAxisSensorFusionEnabled(parameters.sixaxis_handle, is_enabled);
592
593 LOG_DEBUG(Service_HID,
594 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
595 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
596 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
597
598 IPC::ResponseBuilder rb{ctx, 3};
599 rb.Push(result);
600 rb.Push(is_enabled);
601}
602
603void Hid::EnableSixAxisSensorFusion(HLERequestContext& ctx) {
604 IPC::RequestParser rp{ctx};
605 struct Parameters {
606 bool enable_sixaxis_sensor_fusion;
607 INSERT_PADDING_BYTES_NOINIT(3);
608 Core::HID::SixAxisSensorHandle sixaxis_handle;
609 u64 applet_resource_user_id;
610 };
611 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
612
613 const auto parameters{rp.PopRaw<Parameters>()};
614
615 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
616 const auto result = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle,
617 parameters.enable_sixaxis_sensor_fusion);
618
619 LOG_DEBUG(Service_HID,
620 "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
621 "device_index={}, applet_resource_user_id={}",
622 parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
623 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
624 parameters.applet_resource_user_id);
625
626 IPC::ResponseBuilder rb{ctx, 2};
627 rb.Push(result);
628}
629
630void Hid::SetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
631 IPC::RequestParser rp{ctx};
632 struct Parameters {
633 Core::HID::SixAxisSensorHandle sixaxis_handle;
634 Core::HID::SixAxisSensorFusionParameters sixaxis_fusion;
635 INSERT_PADDING_WORDS_NOINIT(1);
636 u64 applet_resource_user_id;
637 };
638 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
639
640 const auto parameters{rp.PopRaw<Parameters>()};
641
642 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
643 const auto result =
644 controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion);
645
646 LOG_DEBUG(Service_HID,
647 "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, "
648 "parameter2={}, applet_resource_user_id={}",
649 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
650 parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1,
651 parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id);
652
653 IPC::ResponseBuilder rb{ctx, 2};
654 rb.Push(result);
655}
656
657void Hid::GetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
658 IPC::RequestParser rp{ctx};
659 struct Parameters {
660 Core::HID::SixAxisSensorHandle sixaxis_handle;
661 INSERT_PADDING_WORDS_NOINIT(1);
662 u64 applet_resource_user_id;
663 };
664 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
665
666 const auto parameters{rp.PopRaw<Parameters>()};
667
668 Core::HID::SixAxisSensorFusionParameters fusion_parameters{};
669 const auto& controller =
670 GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
671 const auto result =
672 controller.GetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
673
674 LOG_DEBUG(Service_HID,
675 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
676 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
677 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
678
679 IPC::ResponseBuilder rb{ctx, 4};
680 rb.Push(result);
681 rb.PushRaw(fusion_parameters);
682}
683
684void Hid::ResetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
685 IPC::RequestParser rp{ctx};
686 struct Parameters {
687 Core::HID::SixAxisSensorHandle sixaxis_handle;
688 INSERT_PADDING_WORDS_NOINIT(1);
689 u64 applet_resource_user_id;
690 };
691 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
692
693 const auto parameters{rp.PopRaw<Parameters>()};
694
695 // Since these parameters are unknown just use what HW outputs
696 const Core::HID::SixAxisSensorFusionParameters fusion_parameters{
697 .parameter1 = 0.03f,
698 .parameter2 = 0.4f,
699 };
700 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
701 const auto result1 =
702 controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
703 const auto result2 = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle, true);
704
705 LOG_DEBUG(Service_HID,
706 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
707 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
708 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
709
710 IPC::ResponseBuilder rb{ctx, 2};
711 if (result1.IsError()) {
712 rb.Push(result1);
713 return;
714 }
715 rb.Push(result2);
716}
717
718void Hid::SetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
719 IPC::RequestParser rp{ctx};
720 const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()};
721 const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()};
722 const auto applet_resource_user_id{rp.Pop<u64>()};
723
724 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
725 const auto result = controller.SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode);
726
727 LOG_DEBUG(Service_HID,
728 "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
729 "applet_resource_user_id={}",
730 sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index,
731 drift_mode, applet_resource_user_id);
732
733 IPC::ResponseBuilder rb{ctx, 2};
734 rb.Push(result);
735}
736
737void Hid::GetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
738 IPC::RequestParser rp{ctx};
739 struct Parameters {
740 Core::HID::SixAxisSensorHandle sixaxis_handle;
741 INSERT_PADDING_WORDS_NOINIT(1);
742 u64 applet_resource_user_id;
743 };
744 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
745
746 const auto parameters{rp.PopRaw<Parameters>()};
747
748 auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
749 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
750 const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
751
752 LOG_DEBUG(Service_HID,
753 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
754 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
755 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
756
757 IPC::ResponseBuilder rb{ctx, 3};
758 rb.Push(result);
759 rb.PushEnum(drift_mode);
760}
761
762void Hid::ResetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
763 IPC::RequestParser rp{ctx};
764 struct Parameters {
765 Core::HID::SixAxisSensorHandle sixaxis_handle;
766 INSERT_PADDING_WORDS_NOINIT(1);
767 u64 applet_resource_user_id;
768 };
769 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
770
771 const auto parameters{rp.PopRaw<Parameters>()};
772
773 const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
774 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
775 const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
776
777 LOG_DEBUG(Service_HID,
778 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
779 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
780 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
781
782 IPC::ResponseBuilder rb{ctx, 2};
783 rb.Push(result);
784}
785
786void Hid::IsSixAxisSensorAtRest(HLERequestContext& ctx) {
787 IPC::RequestParser rp{ctx};
788 struct Parameters {
789 Core::HID::SixAxisSensorHandle sixaxis_handle;
790 INSERT_PADDING_WORDS_NOINIT(1);
791 u64 applet_resource_user_id;
792 };
793 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
794
795 const auto parameters{rp.PopRaw<Parameters>()};
796
797 bool is_at_rest{};
798 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
799 controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
800
801 LOG_DEBUG(Service_HID,
802 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
803 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
804 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
805
806 IPC::ResponseBuilder rb{ctx, 3};
807 rb.Push(ResultSuccess);
808 rb.Push(is_at_rest);
809}
810
811void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx) {
812 IPC::RequestParser rp{ctx};
813 struct Parameters {
814 Core::HID::SixAxisSensorHandle sixaxis_handle;
815 INSERT_PADDING_WORDS_NOINIT(1);
816 u64 applet_resource_user_id;
817 };
818 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
819
820 const auto parameters{rp.PopRaw<Parameters>()};
821
822 bool is_firmware_available{};
823 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
824 controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle,
825 is_firmware_available);
826
827 LOG_WARNING(
828 Service_HID,
829 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
830 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
831 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
832
833 IPC::ResponseBuilder rb{ctx, 3};
834 rb.Push(ResultSuccess);
835 rb.Push(is_firmware_available);
836}
837
838void Hid::EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx) {
839 IPC::RequestParser rp{ctx};
840 struct Parameters {
841 bool enabled;
842 Core::HID::SixAxisSensorHandle sixaxis_handle;
843 u64 applet_resource_user_id;
844 };
845 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
846
847 const auto parameters{rp.PopRaw<Parameters>()};
848
849 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
850 const auto result = controller.EnableSixAxisSensorUnalteredPassthrough(
851 parameters.sixaxis_handle, parameters.enabled);
852
853 LOG_DEBUG(Service_HID,
854 "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, "
855 "applet_resource_user_id={}",
856 parameters.enabled, parameters.sixaxis_handle.npad_type,
857 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
858 parameters.applet_resource_user_id);
859
860 IPC::ResponseBuilder rb{ctx, 2};
861 rb.Push(result);
862}
863
864void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx) {
865 IPC::RequestParser rp{ctx};
866 struct Parameters {
867 Core::HID::SixAxisSensorHandle sixaxis_handle;
868 INSERT_PADDING_WORDS_NOINIT(1);
869 u64 applet_resource_user_id;
870 };
871 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
872
873 const auto parameters{rp.PopRaw<Parameters>()};
874
875 bool is_unaltered_sisxaxis_enabled{};
876 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
877 const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled(
878 parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled);
879
880 LOG_DEBUG(
881 Service_HID,
882 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
883 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
884 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
885
886 IPC::ResponseBuilder rb{ctx, 3};
887 rb.Push(result);
888 rb.Push(is_unaltered_sisxaxis_enabled);
889}
890
891void Hid::LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx) {
892 IPC::RequestParser rp{ctx};
893 struct Parameters {
894 Core::HID::SixAxisSensorHandle sixaxis_handle;
895 INSERT_PADDING_WORDS_NOINIT(1);
896 u64 applet_resource_user_id;
897 };
898 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
899
900 const auto parameters{rp.PopRaw<Parameters>()};
901
902 Core::HID::SixAxisSensorCalibrationParameter calibration{};
903 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
904 const auto result =
905 controller.LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration);
906
907 LOG_WARNING(
908 Service_HID,
909 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
910 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
911 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
912
913 if (result.IsSuccess()) {
914 ctx.WriteBuffer(calibration);
915 }
916
917 IPC::ResponseBuilder rb{ctx, 2};
918 rb.Push(result);
919}
920
921void Hid::GetSixAxisSensorIcInformation(HLERequestContext& ctx) {
922 IPC::RequestParser rp{ctx};
923 struct Parameters {
924 Core::HID::SixAxisSensorHandle sixaxis_handle;
925 INSERT_PADDING_WORDS_NOINIT(1);
926 u64 applet_resource_user_id;
927 };
928 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
929
930 const auto parameters{rp.PopRaw<Parameters>()};
931
932 Core::HID::SixAxisSensorIcInformation ic_information{};
933 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
934 const auto result =
935 controller.GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information);
936
937 LOG_WARNING(
938 Service_HID,
939 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
940 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
941 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
942
943 if (result.IsSuccess()) {
944 ctx.WriteBuffer(ic_information);
945 }
946
947 IPC::ResponseBuilder rb{ctx, 2};
948 rb.Push(result);
949}
950
951void Hid::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx) {
952 IPC::RequestParser rp{ctx};
953 struct Parameters {
954 Core::HID::SixAxisSensorHandle sixaxis_handle;
955 INSERT_PADDING_WORDS_NOINIT(1);
956 u64 applet_resource_user_id;
957 };
958 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
959
960 const auto parameters{rp.PopRaw<Parameters>()};
961
962 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
963 const auto result =
964 controller.ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle);
965
966 LOG_WARNING(
967 Service_HID,
968 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
969 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
970 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
971
972 IPC::ResponseBuilder rb{ctx, 2};
973 rb.Push(result);
974}
975
976void Hid::ActivateGesture(HLERequestContext& ctx) {
977 IPC::RequestParser rp{ctx};
978 struct Parameters {
979 u32 unknown;
980 INSERT_PADDING_WORDS_NOINIT(1);
981 u64 applet_resource_user_id;
982 };
983 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
984
985 const auto parameters{rp.PopRaw<Parameters>()};
986
987 applet_resource->ActivateController(HidController::Gesture);
988
989 LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}",
990 parameters.unknown, parameters.applet_resource_user_id);
991
992 IPC::ResponseBuilder rb{ctx, 2};
993 rb.Push(ResultSuccess);
994}
995
996void Hid::SetSupportedNpadStyleSet(HLERequestContext& ctx) {
997 IPC::RequestParser rp{ctx};
998 struct Parameters {
999 Core::HID::NpadStyleSet supported_styleset;
1000 INSERT_PADDING_WORDS_NOINIT(1);
1001 u64 applet_resource_user_id;
1002 };
1003 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1004
1005 const auto parameters{rp.PopRaw<Parameters>()};
1006
1007 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1008 .SetSupportedStyleSet({parameters.supported_styleset});
1009
1010 LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}",
1011 parameters.supported_styleset, parameters.applet_resource_user_id);
1012
1013 IPC::ResponseBuilder rb{ctx, 2};
1014 rb.Push(ResultSuccess);
1015}
1016
1017void Hid::GetSupportedNpadStyleSet(HLERequestContext& ctx) {
1018 IPC::RequestParser rp{ctx};
1019 const auto applet_resource_user_id{rp.Pop<u64>()};
1020
1021 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1022
1023 IPC::ResponseBuilder rb{ctx, 3};
1024 rb.Push(ResultSuccess);
1025 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1026 .GetSupportedStyleSet()
1027 .raw);
1028}
1029
1030void Hid::SetSupportedNpadIdType(HLERequestContext& ctx) {
1031 IPC::RequestParser rp{ctx};
1032 const auto applet_resource_user_id{rp.Pop<u64>()};
1033
1034 const auto result = applet_resource->GetController<Controller_NPad>(HidController::NPad)
1035 .SetSupportedNpadIdTypes(ctx.ReadBuffer());
1036
1037 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1038
1039 IPC::ResponseBuilder rb{ctx, 2};
1040 rb.Push(result);
1041}
1042
1043void Hid::ActivateNpad(HLERequestContext& ctx) {
1044 IPC::RequestParser rp{ctx};
1045 const auto applet_resource_user_id{rp.Pop<u64>()};
1046
1047 applet_resource->ActivateController(HidController::NPad);
1048
1049 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1050
1051 IPC::ResponseBuilder rb{ctx, 2};
1052 rb.Push(ResultSuccess);
1053}
1054
1055void Hid::DeactivateNpad(HLERequestContext& ctx) {
1056 IPC::RequestParser rp{ctx};
1057 const auto applet_resource_user_id{rp.Pop<u64>()};
1058
1059 applet_resource->DeactivateController(HidController::NPad);
1060
1061 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1062
1063 IPC::ResponseBuilder rb{ctx, 2};
1064 rb.Push(ResultSuccess);
1065}
1066
1067void Hid::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) {
1068 IPC::RequestParser rp{ctx};
1069 struct Parameters {
1070 Core::HID::NpadIdType npad_id;
1071 INSERT_PADDING_WORDS_NOINIT(1);
1072 u64 applet_resource_user_id;
1073 u64 unknown;
1074 };
1075 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1076
1077 const auto parameters{rp.PopRaw<Parameters>()};
1078
1079 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
1080 parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
1081
1082 // Games expect this event to be signaled after calling this function
1083 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1084 .SignalStyleSetChangedEvent(parameters.npad_id);
1085
1086 IPC::ResponseBuilder rb{ctx, 2, 1};
1087 rb.Push(ResultSuccess);
1088 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1089 .GetStyleSetChangedEvent(parameters.npad_id));
1090}
1091
1092void Hid::DisconnectNpad(HLERequestContext& ctx) {
1093 IPC::RequestParser rp{ctx};
1094 struct Parameters {
1095 Core::HID::NpadIdType npad_id;
1096 INSERT_PADDING_WORDS_NOINIT(1);
1097 u64 applet_resource_user_id;
1098 };
1099 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1100
1101 const auto parameters{rp.PopRaw<Parameters>()};
1102
1103 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1104 controller.DisconnectNpad(parameters.npad_id);
1105
1106 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1107 parameters.applet_resource_user_id);
1108
1109 IPC::ResponseBuilder rb{ctx, 2};
1110 rb.Push(ResultSuccess);
1111}
1112
1113void Hid::GetPlayerLedPattern(HLERequestContext& ctx) {
1114 IPC::RequestParser rp{ctx};
1115 const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
1116
1117 Core::HID::LedPattern pattern{0, 0, 0, 0};
1118 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1119 const auto result = controller.GetLedPattern(npad_id, pattern);
1120
1121 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
1122
1123 IPC::ResponseBuilder rb{ctx, 4};
1124 rb.Push(result);
1125 rb.Push(pattern.raw);
1126}
1127
1128void Hid::ActivateNpadWithRevision(HLERequestContext& ctx) {
1129 // Should have no effect with how our npad sets up the data
1130 IPC::RequestParser rp{ctx};
1131 struct Parameters {
1132 s32 revision;
1133 INSERT_PADDING_WORDS_NOINIT(1);
1134 u64 applet_resource_user_id;
1135 };
1136 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1137
1138 const auto parameters{rp.PopRaw<Parameters>()};
1139
1140 applet_resource->ActivateController(HidController::NPad);
1141
1142 LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision,
1143 parameters.applet_resource_user_id);
1144
1145 IPC::ResponseBuilder rb{ctx, 2};
1146 rb.Push(ResultSuccess);
1147}
1148
1149void Hid::SetNpadJoyHoldType(HLERequestContext& ctx) {
1150 IPC::RequestParser rp{ctx};
1151 const auto applet_resource_user_id{rp.Pop<u64>()};
1152 const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()};
1153
1154 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type);
1155
1156 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
1157 applet_resource_user_id, hold_type);
1158
1159 IPC::ResponseBuilder rb{ctx, 2};
1160 rb.Push(ResultSuccess);
1161}
1162
1163void Hid::GetNpadJoyHoldType(HLERequestContext& ctx) {
1164 IPC::RequestParser rp{ctx};
1165 const auto applet_resource_user_id{rp.Pop<u64>()};
1166
1167 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1168
1169 IPC::ResponseBuilder rb{ctx, 4};
1170 rb.Push(ResultSuccess);
1171 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
1172}
1173
1174void Hid::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) {
1175 IPC::RequestParser rp{ctx};
1176 struct Parameters {
1177 Core::HID::NpadIdType npad_id;
1178 INSERT_PADDING_WORDS_NOINIT(1);
1179 u64 applet_resource_user_id;
1180 };
1181 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1182
1183 const auto parameters{rp.PopRaw<Parameters>()};
1184
1185 Core::HID::NpadIdType new_npad_id{};
1186 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1187 controller.SetNpadMode(new_npad_id, parameters.npad_id,
1188 Controller_NPad::NpadJoyDeviceType::Left,
1189 Controller_NPad::NpadJoyAssignmentMode::Single);
1190
1191 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1192 parameters.applet_resource_user_id);
1193
1194 IPC::ResponseBuilder rb{ctx, 2};
1195 rb.Push(ResultSuccess);
1196}
1197
1198void Hid::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
1199 IPC::RequestParser rp{ctx};
1200 struct Parameters {
1201 Core::HID::NpadIdType npad_id;
1202 INSERT_PADDING_WORDS_NOINIT(1);
1203 u64 applet_resource_user_id;
1204 Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
1205 };
1206 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1207
1208 const auto parameters{rp.PopRaw<Parameters>()};
1209
1210 Core::HID::NpadIdType new_npad_id{};
1211 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1212 controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
1213 Controller_NPad::NpadJoyAssignmentMode::Single);
1214
1215 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1216 parameters.npad_id, parameters.applet_resource_user_id,
1217 parameters.npad_joy_device_type);
1218
1219 IPC::ResponseBuilder rb{ctx, 2};
1220 rb.Push(ResultSuccess);
1221}
1222
1223void Hid::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
1224 IPC::RequestParser rp{ctx};
1225 struct Parameters {
1226 Core::HID::NpadIdType npad_id;
1227 INSERT_PADDING_WORDS_NOINIT(1);
1228 u64 applet_resource_user_id;
1229 };
1230 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1231
1232 const auto parameters{rp.PopRaw<Parameters>()};
1233
1234 Core::HID::NpadIdType new_npad_id{};
1235 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1236 controller.SetNpadMode(new_npad_id, parameters.npad_id, {},
1237 Controller_NPad::NpadJoyAssignmentMode::Dual);
1238
1239 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1240 parameters.applet_resource_user_id);
1241
1242 IPC::ResponseBuilder rb{ctx, 2};
1243 rb.Push(ResultSuccess);
1244}
1245
1246void Hid::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) {
1247 IPC::RequestParser rp{ctx};
1248 const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
1249 const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
1250 const auto applet_resource_user_id{rp.Pop<u64>()};
1251
1252 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1253 const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
1254
1255 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
1256 npad_id_1, npad_id_2, applet_resource_user_id);
1257
1258 IPC::ResponseBuilder rb{ctx, 2};
1259 rb.Push(result);
1260}
1261
1262void Hid::StartLrAssignmentMode(HLERequestContext& ctx) {
1263 IPC::RequestParser rp{ctx};
1264 const auto applet_resource_user_id{rp.Pop<u64>()};
1265
1266 applet_resource->GetController<Controller_NPad>(HidController::NPad).StartLRAssignmentMode();
1267
1268 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1269
1270 IPC::ResponseBuilder rb{ctx, 2};
1271 rb.Push(ResultSuccess);
1272}
1273
1274void Hid::StopLrAssignmentMode(HLERequestContext& ctx) {
1275 IPC::RequestParser rp{ctx};
1276 const auto applet_resource_user_id{rp.Pop<u64>()};
1277
1278 applet_resource->GetController<Controller_NPad>(HidController::NPad).StopLRAssignmentMode();
1279
1280 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1281
1282 IPC::ResponseBuilder rb{ctx, 2};
1283 rb.Push(ResultSuccess);
1284}
1285
1286void Hid::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
1287 IPC::RequestParser rp{ctx};
1288 const auto applet_resource_user_id{rp.Pop<u64>()};
1289 const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};
1290
1291 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1292 .SetNpadHandheldActivationMode(activation_mode);
1293
1294 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}",
1295 applet_resource_user_id, activation_mode);
1296
1297 IPC::ResponseBuilder rb{ctx, 2};
1298 rb.Push(ResultSuccess);
1299}
1300
1301void Hid::GetNpadHandheldActivationMode(HLERequestContext& ctx) {
1302 IPC::RequestParser rp{ctx};
1303 const auto applet_resource_user_id{rp.Pop<u64>()};
1304
1305 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1306
1307 IPC::ResponseBuilder rb{ctx, 4};
1308 rb.Push(ResultSuccess);
1309 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1310 .GetNpadHandheldActivationMode());
1311}
1312
1313void Hid::SwapNpadAssignment(HLERequestContext& ctx) {
1314 IPC::RequestParser rp{ctx};
1315 const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
1316 const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
1317 const auto applet_resource_user_id{rp.Pop<u64>()};
1318
1319 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1320 const auto result = controller.SwapNpadAssignment(npad_id_1, npad_id_2);
1321
1322 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
1323 npad_id_1, npad_id_2, applet_resource_user_id);
1324
1325 IPC::ResponseBuilder rb{ctx, 2};
1326 rb.Push(result);
1327}
1328
1329void Hid::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx) {
1330 IPC::RequestParser rp{ctx};
1331 struct Parameters {
1332 Core::HID::NpadIdType npad_id;
1333 INSERT_PADDING_WORDS_NOINIT(1);
1334 u64 applet_resource_user_id;
1335 };
1336 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1337
1338 const auto parameters{rp.PopRaw<Parameters>()};
1339
1340 bool is_enabled = false;
1341 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1342 const auto result =
1343 controller.IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled);
1344
1345 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
1346 parameters.npad_id, parameters.applet_resource_user_id);
1347
1348 IPC::ResponseBuilder rb{ctx, 3};
1349 rb.Push(result);
1350 rb.Push(is_enabled);
1351}
1352
1353void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) {
1354 IPC::RequestParser rp{ctx};
1355 struct Parameters {
1356 bool is_enabled;
1357 INSERT_PADDING_BYTES_NOINIT(3);
1358 Core::HID::NpadIdType npad_id;
1359 u64 applet_resource_user_id;
1360 };
1361 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1362
1363 const auto parameters{rp.PopRaw<Parameters>()};
1364
1365 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1366 const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled(
1367 parameters.is_enabled, parameters.npad_id);
1368
1369 LOG_DEBUG(Service_HID,
1370 "(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}",
1371 parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id);
1372
1373 IPC::ResponseBuilder rb{ctx, 2};
1374 rb.Push(result);
1375}
1376
1377void Hid::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx) {
1378 IPC::RequestParser rp{ctx};
1379 struct Parameters {
1380 Core::HID::NpadIdType npad_id;
1381 INSERT_PADDING_WORDS_NOINIT(1);
1382 u64 applet_resource_user_id;
1383 Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
1384 };
1385 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1386
1387 const auto parameters{rp.PopRaw<Parameters>()};
1388
1389 Core::HID::NpadIdType new_npad_id{};
1390 auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1391 const auto is_reassigned =
1392 controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
1393 Controller_NPad::NpadJoyAssignmentMode::Single);
1394
1395 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1396 parameters.npad_id, parameters.applet_resource_user_id,
1397 parameters.npad_joy_device_type);
1398
1399 IPC::ResponseBuilder rb{ctx, 4};
1400 rb.Push(ResultSuccess);
1401 rb.Push(is_reassigned);
1402 rb.PushEnum(new_npad_id);
1403}
1404
1405void Hid::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
1406 IPC::RequestParser rp{ctx};
1407 struct Parameters {
1408 bool analog_stick_use_center_clamp;
1409 INSERT_PADDING_BYTES_NOINIT(7);
1410 u64 applet_resource_user_id;
1411 };
1412 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1413
1414 const auto parameters{rp.PopRaw<Parameters>()};
1415
1416 GetAppletResource()
1417 ->GetController<Controller_NPad>(HidController::NPad)
1418 .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
1419
1420 LOG_WARNING(Service_HID,
1421 "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
1422 parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id);
1423
1424 IPC::ResponseBuilder rb{ctx, 2};
1425 rb.Push(ResultSuccess);
1426}
1427
1428void Hid::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
1429 IPC::RequestParser rp{ctx};
1430 struct Parameters {
1431 Core::HID::NpadStyleSet npad_styleset;
1432 INSERT_PADDING_WORDS_NOINIT(1);
1433 u64 applet_resource_user_id;
1434 Core::HID::NpadButton button;
1435 };
1436 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1437
1438 const auto parameters{rp.PopRaw<Parameters>()};
1439
1440 LOG_WARNING(Service_HID,
1441 "(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}",
1442 parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
1443
1444 IPC::ResponseBuilder rb{ctx, 2};
1445 rb.Push(ResultSuccess);
1446}
1447
1448void Hid::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
1449 IPC::RequestParser rp{ctx};
1450 const auto applet_resource_user_id{rp.Pop<u64>()};
1451
1452 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1453 applet_resource_user_id);
1454
1455 IPC::ResponseBuilder rb{ctx, 2};
1456 rb.Push(ResultSuccess);
1457}
1458
1459void Hid::GetVibrationDeviceInfo(HLERequestContext& ctx) {
1460 IPC::RequestParser rp{ctx};
1461 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
1462 const auto& controller =
1463 GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
1464
1465 Core::HID::VibrationDeviceInfo vibration_device_info;
1466 bool check_device_index = false;
1467
1468 switch (vibration_device_handle.npad_type) {
1469 case Core::HID::NpadStyleIndex::ProController:
1470 case Core::HID::NpadStyleIndex::Handheld:
1471 case Core::HID::NpadStyleIndex::JoyconDual:
1472 case Core::HID::NpadStyleIndex::JoyconLeft:
1473 case Core::HID::NpadStyleIndex::JoyconRight:
1474 vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
1475 check_device_index = true;
1476 break;
1477 case Core::HID::NpadStyleIndex::GameCube:
1478 vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
1479 break;
1480 case Core::HID::NpadStyleIndex::N64:
1481 vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
1482 break;
1483 default:
1484 vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
1485 break;
1486 }
1487
1488 vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
1489 if (check_device_index) {
1490 switch (vibration_device_handle.device_index) {
1491 case Core::HID::DeviceIndex::Left:
1492 vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
1493 break;
1494 case Core::HID::DeviceIndex::Right:
1495 vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
1496 break;
1497 case Core::HID::DeviceIndex::None:
1498 default:
1499 ASSERT_MSG(false, "DeviceIndex should never be None!");
1500 break;
1501 }
1502 }
1503
1504 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
1505 vibration_device_info.type, vibration_device_info.position);
1506
1507 const auto result = controller.IsDeviceHandleValid(vibration_device_handle);
1508 if (result.IsError()) {
1509 IPC::ResponseBuilder rb{ctx, 2};
1510 rb.Push(result);
1511 return;
1512 }
1513
1514 IPC::ResponseBuilder rb{ctx, 4};
1515 rb.Push(ResultSuccess);
1516 rb.PushRaw(vibration_device_info);
1517}
1518
1519void Hid::SendVibrationValue(HLERequestContext& ctx) {
1520 IPC::RequestParser rp{ctx};
1521 struct Parameters {
1522 Core::HID::VibrationDeviceHandle vibration_device_handle;
1523 Core::HID::VibrationValue vibration_value;
1524 INSERT_PADDING_WORDS_NOINIT(1);
1525 u64 applet_resource_user_id;
1526 };
1527 static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
1528
1529 const auto parameters{rp.PopRaw<Parameters>()};
1530
1531 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1532 .VibrateController(parameters.vibration_device_handle, parameters.vibration_value);
1533
1534 LOG_DEBUG(Service_HID,
1535 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1536 parameters.vibration_device_handle.npad_type,
1537 parameters.vibration_device_handle.npad_id,
1538 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1539
1540 IPC::ResponseBuilder rb{ctx, 2};
1541 rb.Push(ResultSuccess);
1542}
1543
1544void Hid::GetActualVibrationValue(HLERequestContext& ctx) {
1545 IPC::RequestParser rp{ctx};
1546 struct Parameters {
1547 Core::HID::VibrationDeviceHandle vibration_device_handle;
1548 INSERT_PADDING_WORDS_NOINIT(1);
1549 u64 applet_resource_user_id;
1550 };
1551 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1552
1553 const auto parameters{rp.PopRaw<Parameters>()};
1554
1555 LOG_DEBUG(Service_HID,
1556 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1557 parameters.vibration_device_handle.npad_type,
1558 parameters.vibration_device_handle.npad_id,
1559 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1560
1561 IPC::ResponseBuilder rb{ctx, 6};
1562 rb.Push(ResultSuccess);
1563 rb.PushRaw(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1564 .GetLastVibration(parameters.vibration_device_handle));
1565}
1566
1567void Hid::CreateActiveVibrationDeviceList(HLERequestContext& ctx) {
1568 LOG_DEBUG(Service_HID, "called");
1569
1570 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1571 rb.Push(ResultSuccess);
1572 rb.PushIpcInterface<IActiveVibrationDeviceList>(system, applet_resource);
1573}
1574
1575void Hid::PermitVibration(HLERequestContext& ctx) {
1576 IPC::RequestParser rp{ctx};
1577 const auto can_vibrate{rp.Pop<bool>()};
1578
1579 // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value
1580 // by converting it to a bool
1581 Settings::values.vibration_enabled.SetValue(can_vibrate);
1582
1583 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
1584
1585 IPC::ResponseBuilder rb{ctx, 2};
1586 rb.Push(ResultSuccess);
1587}
1588
1589void Hid::IsVibrationPermitted(HLERequestContext& ctx) {
1590 LOG_DEBUG(Service_HID, "called");
1591
1592 // nnSDK checks if a float is greater than zero. We return the bool we stored earlier
1593 const auto is_enabled = Settings::values.vibration_enabled.GetValue();
1594
1595 IPC::ResponseBuilder rb{ctx, 3};
1596 rb.Push(ResultSuccess);
1597 rb.Push(is_enabled);
1598}
1599
1600void Hid::SendVibrationValues(HLERequestContext& ctx) {
1601 IPC::RequestParser rp{ctx};
1602 const auto applet_resource_user_id{rp.Pop<u64>()};
1603
1604 const auto handle_data = ctx.ReadBuffer(0);
1605 const auto handle_count = ctx.GetReadBufferNumElements<Core::HID::VibrationDeviceHandle>(0);
1606 const auto vibration_data = ctx.ReadBuffer(1);
1607 const auto vibration_count = ctx.GetReadBufferNumElements<Core::HID::VibrationValue>(1);
1608
1609 auto vibration_device_handles =
1610 std::span(reinterpret_cast<const Core::HID::VibrationDeviceHandle*>(handle_data.data()),
1611 handle_count);
1612 auto vibration_values = std::span(
1613 reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
1614
1615 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1616 .VibrateControllers(vibration_device_handles, vibration_values);
1617
1618 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1619
1620 IPC::ResponseBuilder rb{ctx, 2};
1621 rb.Push(ResultSuccess);
1622}
1623
1624void Hid::SendVibrationGcErmCommand(HLERequestContext& ctx) {
1625 IPC::RequestParser rp{ctx};
1626 struct Parameters {
1627 Core::HID::VibrationDeviceHandle vibration_device_handle;
1628 INSERT_PADDING_WORDS_NOINIT(1);
1629 u64 applet_resource_user_id;
1630 Core::HID::VibrationGcErmCommand gc_erm_command;
1631 };
1632 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1633
1634 const auto parameters{rp.PopRaw<Parameters>()};
1635
1636 /**
1637 * Note: This uses yuzu-specific behavior such that the StopHard command produces
1638 * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below,
1639 * in order to differentiate between Stop and StopHard commands.
1640 * This is done to reuse the controller vibration functions made for regular controllers.
1641 */
1642 const auto vibration_value = [parameters] {
1643 switch (parameters.gc_erm_command) {
1644 case Core::HID::VibrationGcErmCommand::Stop:
1645 return Core::HID::VibrationValue{
1646 .low_amplitude = 0.0f,
1647 .low_frequency = 160.0f,
1648 .high_amplitude = 0.0f,
1649 .high_frequency = 320.0f,
1650 };
1651 case Core::HID::VibrationGcErmCommand::Start:
1652 return Core::HID::VibrationValue{
1653 .low_amplitude = 1.0f,
1654 .low_frequency = 160.0f,
1655 .high_amplitude = 1.0f,
1656 .high_frequency = 320.0f,
1657 };
1658 case Core::HID::VibrationGcErmCommand::StopHard:
1659 return Core::HID::VibrationValue{
1660 .low_amplitude = 0.0f,
1661 .low_frequency = 0.0f,
1662 .high_amplitude = 0.0f,
1663 .high_frequency = 0.0f,
1664 };
1665 default:
1666 return Core::HID::DEFAULT_VIBRATION_VALUE;
1667 }
1668 }();
1669
1670 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1671 .VibrateController(parameters.vibration_device_handle, vibration_value);
1672
1673 LOG_DEBUG(Service_HID,
1674 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
1675 "gc_erm_command={}",
1676 parameters.vibration_device_handle.npad_type,
1677 parameters.vibration_device_handle.npad_id,
1678 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
1679 parameters.gc_erm_command);
1680
1681 IPC::ResponseBuilder rb{ctx, 2};
1682 rb.Push(ResultSuccess);
1683}
1684
1685void Hid::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
1686 IPC::RequestParser rp{ctx};
1687 struct Parameters {
1688 Core::HID::VibrationDeviceHandle vibration_device_handle;
1689 INSERT_PADDING_WORDS_NOINIT(1);
1690 u64 applet_resource_user_id;
1691 };
1692
1693 const auto parameters{rp.PopRaw<Parameters>()};
1694
1695 const auto last_vibration = applet_resource->GetController<Controller_NPad>(HidController::NPad)
1696 .GetLastVibration(parameters.vibration_device_handle);
1697
1698 const auto gc_erm_command = [last_vibration] {
1699 if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
1700 return Core::HID::VibrationGcErmCommand::Start;
1701 }
1702
1703 /**
1704 * Note: This uses yuzu-specific behavior such that the StopHard command produces
1705 * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function
1706 * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
1707 * This is done to reuse the controller vibration functions made for regular controllers.
1708 */
1709 if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) {
1710 return Core::HID::VibrationGcErmCommand::StopHard;
1711 }
1712
1713 return Core::HID::VibrationGcErmCommand::Stop;
1714 }();
1715
1716 LOG_DEBUG(Service_HID,
1717 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1718 parameters.vibration_device_handle.npad_type,
1719 parameters.vibration_device_handle.npad_id,
1720 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1721
1722 IPC::ResponseBuilder rb{ctx, 4};
1723 rb.Push(ResultSuccess);
1724 rb.PushEnum(gc_erm_command);
1725}
1726
1727void Hid::BeginPermitVibrationSession(HLERequestContext& ctx) {
1728 IPC::RequestParser rp{ctx};
1729 const auto applet_resource_user_id{rp.Pop<u64>()};
1730
1731 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1732 .SetPermitVibrationSession(true);
1733
1734 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1735
1736 IPC::ResponseBuilder rb{ctx, 2};
1737 rb.Push(ResultSuccess);
1738}
1739
1740void Hid::EndPermitVibrationSession(HLERequestContext& ctx) {
1741 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1742 .SetPermitVibrationSession(false);
1743
1744 LOG_DEBUG(Service_HID, "called");
1745
1746 IPC::ResponseBuilder rb{ctx, 2};
1747 rb.Push(ResultSuccess);
1748}
1749
1750void Hid::IsVibrationDeviceMounted(HLERequestContext& ctx) {
1751 IPC::RequestParser rp{ctx};
1752 struct Parameters {
1753 Core::HID::VibrationDeviceHandle vibration_device_handle;
1754 INSERT_PADDING_WORDS_NOINIT(1);
1755 u64 applet_resource_user_id;
1756 };
1757 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1758
1759 const auto parameters{rp.PopRaw<Parameters>()};
1760
1761 LOG_DEBUG(Service_HID,
1762 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1763 parameters.vibration_device_handle.npad_type,
1764 parameters.vibration_device_handle.npad_id,
1765 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1766
1767 IPC::ResponseBuilder rb{ctx, 3};
1768 rb.Push(ResultSuccess);
1769 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1770 .IsVibrationDeviceMounted(parameters.vibration_device_handle));
1771}
1772
1773void Hid::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {
1774 IPC::RequestParser rp{ctx};
1775 const auto applet_resource_user_id{rp.Pop<u64>()};
1776
1777 applet_resource->ActivateController(HidController::ConsoleSixAxisSensor);
1778
1779 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1780
1781 IPC::ResponseBuilder rb{ctx, 2};
1782 rb.Push(ResultSuccess);
1783}
1784
1785void Hid::StartConsoleSixAxisSensor(HLERequestContext& ctx) {
1786 IPC::RequestParser rp{ctx};
1787 struct Parameters {
1788 Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
1789 INSERT_PADDING_WORDS_NOINIT(1);
1790 u64 applet_resource_user_id;
1791 };
1792 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1793
1794 const auto parameters{rp.PopRaw<Parameters>()};
1795
1796 LOG_WARNING(Service_HID,
1797 "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
1798 parameters.console_sixaxis_handle.unknown_1,
1799 parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
1800
1801 IPC::ResponseBuilder rb{ctx, 2};
1802 rb.Push(ResultSuccess);
1803}
1804
1805void Hid::StopConsoleSixAxisSensor(HLERequestContext& ctx) {
1806 IPC::RequestParser rp{ctx};
1807 struct Parameters {
1808 Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
1809 INSERT_PADDING_WORDS_NOINIT(1);
1810 u64 applet_resource_user_id;
1811 };
1812 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1813
1814 const auto parameters{rp.PopRaw<Parameters>()};
1815
1816 LOG_WARNING(Service_HID,
1817 "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
1818 parameters.console_sixaxis_handle.unknown_1,
1819 parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
1820
1821 IPC::ResponseBuilder rb{ctx, 2};
1822 rb.Push(ResultSuccess);
1823}
1824
1825void Hid::ActivateSevenSixAxisSensor(HLERequestContext& ctx) {
1826 IPC::RequestParser rp{ctx};
1827 const auto applet_resource_user_id{rp.Pop<u64>()};
1828
1829 applet_resource->ActivateController(HidController::ConsoleSixAxisSensor);
1830
1831 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1832
1833 IPC::ResponseBuilder rb{ctx, 2};
1834 rb.Push(ResultSuccess);
1835}
1836
1837void Hid::StartSevenSixAxisSensor(HLERequestContext& ctx) {
1838 IPC::RequestParser rp{ctx};
1839 const auto applet_resource_user_id{rp.Pop<u64>()};
1840
1841 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1842 applet_resource_user_id);
1843
1844 IPC::ResponseBuilder rb{ctx, 2};
1845 rb.Push(ResultSuccess);
1846}
1847
1848void Hid::StopSevenSixAxisSensor(HLERequestContext& ctx) {
1849 IPC::RequestParser rp{ctx};
1850 const auto applet_resource_user_id{rp.Pop<u64>()};
1851
1852 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1853 applet_resource_user_id);
1854
1855 IPC::ResponseBuilder rb{ctx, 2};
1856 rb.Push(ResultSuccess);
1857}
1858
1859void Hid::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
1860 IPC::RequestParser rp{ctx};
1861 const auto applet_resource_user_id{rp.Pop<u64>()};
1862 const auto t_mem_1_size{rp.Pop<u64>()};
1863 const auto t_mem_2_size{rp.Pop<u64>()};
1864 const auto t_mem_1_handle{ctx.GetCopyHandle(0)};
1865 const auto t_mem_2_handle{ctx.GetCopyHandle(1)};
1866
1867 ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
1868 ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
1869
1870 auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
1871 t_mem_1_handle);
1872
1873 if (t_mem_1.IsNull()) {
1874 LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
1875 IPC::ResponseBuilder rb{ctx, 2};
1876 rb.Push(ResultUnknown);
1877 return;
1878 }
1879
1880 auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
1881 t_mem_2_handle);
1882
1883 if (t_mem_2.IsNull()) {
1884 LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
1885 IPC::ResponseBuilder rb{ctx, 2};
1886 rb.Push(ResultUnknown);
1887 return;
1888 }
1889
1890 ASSERT_MSG(t_mem_1->GetSize() == 0x1000, "t_mem_1 has incorrect size");
1891 ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size");
1892
1893 // Activate console six axis controller
1894 applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1895 .ActivateController();
1896
1897 applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1898 .SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
1899
1900 LOG_WARNING(Service_HID,
1901 "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
1902 "applet_resource_user_id={}",
1903 t_mem_1_handle, t_mem_2_handle, applet_resource_user_id);
1904
1905 IPC::ResponseBuilder rb{ctx, 2};
1906 rb.Push(ResultSuccess);
1907}
1908
1909void Hid::FinalizeSevenSixAxisSensor(HLERequestContext& ctx) {
1910 IPC::RequestParser rp{ctx};
1911 const auto applet_resource_user_id{rp.Pop<u64>()};
1912
1913 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1914 applet_resource_user_id);
1915
1916 IPC::ResponseBuilder rb{ctx, 2};
1917 rb.Push(ResultSuccess);
1918}
1919
1920void Hid::ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx) {
1921 IPC::RequestParser rp{ctx};
1922 const auto applet_resource_user_id{rp.Pop<u64>()};
1923
1924 applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1925 .ResetTimestamp();
1926
1927 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1928
1929 IPC::ResponseBuilder rb{ctx, 2};
1930 rb.Push(ResultSuccess);
1931}
1932
1933void Hid::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
1934 IPC::RequestParser rp{ctx};
1935
1936 LOG_WARNING(Service_HID, "(STUBBED) called");
1937
1938 IPC::ResponseBuilder rb{ctx, 3};
1939 rb.Push(ResultSuccess);
1940 rb.Push(false);
1941}
1942
1943void Hid::GetPalmaConnectionHandle(HLERequestContext& ctx) {
1944 IPC::RequestParser rp{ctx};
1945 struct Parameters {
1946 Core::HID::NpadIdType npad_id;
1947 INSERT_PADDING_WORDS_NOINIT(1);
1948 u64 applet_resource_user_id;
1949 };
1950 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1951
1952 const auto parameters{rp.PopRaw<Parameters>()};
1953
1954 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
1955 parameters.npad_id, parameters.applet_resource_user_id);
1956
1957 Controller_Palma::PalmaConnectionHandle handle;
1958 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
1959 const auto result = controller.GetPalmaConnectionHandle(parameters.npad_id, handle);
1960
1961 IPC::ResponseBuilder rb{ctx, 4};
1962 rb.Push(result);
1963 rb.PushRaw(handle);
1964}
1965
1966void Hid::InitializePalma(HLERequestContext& ctx) {
1967 IPC::RequestParser rp{ctx};
1968 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
1969
1970 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
1971
1972 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
1973 const auto result = controller.InitializePalma(connection_handle);
1974
1975 IPC::ResponseBuilder rb{ctx, 2};
1976 rb.Push(result);
1977}
1978
1979void Hid::AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx) {
1980 IPC::RequestParser rp{ctx};
1981 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
1982
1983 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
1984
1985 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
1986
1987 IPC::ResponseBuilder rb{ctx, 2, 1};
1988 rb.Push(ResultSuccess);
1989 rb.PushCopyObjects(controller.AcquirePalmaOperationCompleteEvent(connection_handle));
1990}
1991
1992void Hid::GetPalmaOperationInfo(HLERequestContext& ctx) {
1993 IPC::RequestParser rp{ctx};
1994 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
1995
1996 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
1997
1998 Controller_Palma::PalmaOperationType operation_type;
1999 Controller_Palma::PalmaOperationData data;
2000 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
2001 const auto result = controller.GetPalmaOperationInfo(connection_handle, operation_type, data);
2002
2003 if (result.IsError()) {
2004 IPC::ResponseBuilder rb{ctx, 2};
2005 rb.Push(result);
2006 }
2007
2008 ctx.WriteBuffer(data);
2009 IPC::ResponseBuilder rb{ctx, 4};
2010 rb.Push(result);
2011 rb.Push(static_cast<u64>(operation_type));
2012}
2013
2014void Hid::PlayPalmaActivity(HLERequestContext& ctx) {
2015 IPC::RequestParser rp{ctx};
2016 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2017 const auto palma_activity{rp.Pop<u64>()};
2018
2019 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, palma_activity={}",
2020 connection_handle.npad_id, palma_activity);
2021
2022 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
2023 const auto result = controller.PlayPalmaActivity(connection_handle, palma_activity);
2024
2025 IPC::ResponseBuilder rb{ctx, 2};
2026 rb.Push(result);
2027}
2028
2029void Hid::SetPalmaFrModeType(HLERequestContext& ctx) {
2030 IPC::RequestParser rp{ctx};
2031 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2032 const auto fr_mode{rp.PopEnum<Controller_Palma::PalmaFrModeType>()};
2033
2034 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, fr_mode={}",
2035 connection_handle.npad_id, fr_mode);
2036
2037 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
2038 const auto result = controller.SetPalmaFrModeType(connection_handle, fr_mode);
2039
2040 IPC::ResponseBuilder rb{ctx, 2};
2041 rb.Push(result);
2042}
2043
2044void Hid::ReadPalmaStep(HLERequestContext& ctx) {
2045 IPC::RequestParser rp{ctx};
2046 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2047
2048 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2049
2050 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
2051 const auto result = controller.ReadPalmaStep(connection_handle);
2052
2053 IPC::ResponseBuilder rb{ctx, 2};
2054 rb.Push(result);
2055}
2056
2057void Hid::EnablePalmaStep(HLERequestContext& ctx) {
2058 IPC::RequestParser rp{ctx};
2059 struct Parameters {
2060 bool is_enabled;
2061 INSERT_PADDING_WORDS_NOINIT(1);
2062 Controller_Palma::PalmaConnectionHandle connection_handle;
2063 };
2064 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2065
2066 const auto parameters{rp.PopRaw<Parameters>()};
2067
2068 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, is_enabled={}",
2069 parameters.connection_handle.npad_id, parameters.is_enabled);
2070
2071 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
2072 const auto result =
2073 controller.EnablePalmaStep(parameters.connection_handle, parameters.is_enabled);
2074
2075 IPC::ResponseBuilder rb{ctx, 2};
2076 rb.Push(result);
2077}
2078
2079void Hid::ResetPalmaStep(HLERequestContext& ctx) {
2080 IPC::RequestParser rp{ctx};
2081 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2082
2083 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2084
2085 auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
2086 const auto result = controller.ResetPalmaStep(connection_handle);
2087
2088 IPC::ResponseBuilder rb{ctx, 2};
2089 rb.Push(result);
2090}
2091
2092void Hid::ReadPalmaApplicationSection(HLERequestContext& ctx) {
2093 LOG_WARNING(Service_HID, "(STUBBED) called");
2094
2095 IPC::ResponseBuilder rb{ctx, 2};
2096 rb.Push(ResultSuccess);
2097}
2098
2099void Hid::WritePalmaApplicationSection(HLERequestContext& ctx) {
2100 LOG_WARNING(Service_HID, "(STUBBED) called");
2101
2102 IPC::ResponseBuilder rb{ctx, 2};
2103 rb.Push(ResultSuccess);
2104}
2105
2106void Hid::ReadPalmaUniqueCode(HLERequestContext& ctx) {
2107 IPC::RequestParser rp{ctx};
2108 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2109
2110 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2111
2112 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2113 .ReadPalmaUniqueCode(connection_handle);
2114
2115 IPC::ResponseBuilder rb{ctx, 2};
2116 rb.Push(ResultSuccess);
2117}
2118
2119void Hid::SetPalmaUniqueCodeInvalid(HLERequestContext& ctx) {
2120 IPC::RequestParser rp{ctx};
2121 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2122
2123 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2124
2125 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2126 .SetPalmaUniqueCodeInvalid(connection_handle);
2127
2128 IPC::ResponseBuilder rb{ctx, 2};
2129 rb.Push(ResultSuccess);
2130}
2131
2132void Hid::WritePalmaActivityEntry(HLERequestContext& ctx) {
2133 LOG_CRITICAL(Service_HID, "(STUBBED) called");
2134
2135 IPC::ResponseBuilder rb{ctx, 2};
2136 rb.Push(ResultSuccess);
2137}
2138
2139void Hid::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) {
2140 IPC::RequestParser rp{ctx};
2141 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2142 const auto unknown{rp.Pop<u64>()};
2143
2144 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
2145
2146 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
2147 connection_handle.npad_id, unknown);
2148
2149 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2150 .WritePalmaRgbLedPatternEntry(connection_handle, unknown);
2151
2152 IPC::ResponseBuilder rb{ctx, 2};
2153 rb.Push(ResultSuccess);
2154}
2155
2156void Hid::WritePalmaWaveEntry(HLERequestContext& ctx) {
2157 IPC::RequestParser rp{ctx};
2158 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2159 const auto wave_set{rp.PopEnum<Controller_Palma::PalmaWaveSet>()};
2160 const auto unknown{rp.Pop<u64>()};
2161 const auto t_mem_size{rp.Pop<u64>()};
2162 const auto t_mem_handle{ctx.GetCopyHandle(0)};
2163 const auto size{rp.Pop<u64>()};
2164
2165 ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
2166
2167 auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
2168 t_mem_handle);
2169
2170 if (t_mem.IsNull()) {
2171 LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
2172 IPC::ResponseBuilder rb{ctx, 2};
2173 rb.Push(ResultUnknown);
2174 return;
2175 }
2176
2177 ASSERT_MSG(t_mem->GetSize() == 0x3000, "t_mem has incorrect size");
2178
2179 LOG_WARNING(Service_HID,
2180 "(STUBBED) called, connection_handle={}, wave_set={}, unknown={}, "
2181 "t_mem_handle=0x{:08X}, t_mem_size={}, size={}",
2182 connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size);
2183
2184 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2185 .WritePalmaWaveEntry(connection_handle, wave_set, t_mem->GetSourceAddress(), t_mem_size);
2186
2187 IPC::ResponseBuilder rb{ctx, 2};
2188 rb.Push(ResultSuccess);
2189}
2190
2191void Hid::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
2192 IPC::RequestParser rp{ctx};
2193 struct Parameters {
2194 s32 database_id_version;
2195 INSERT_PADDING_WORDS_NOINIT(1);
2196 Controller_Palma::PalmaConnectionHandle connection_handle;
2197 };
2198 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2199
2200 const auto parameters{rp.PopRaw<Parameters>()};
2201
2202 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, database_id_version={}",
2203 parameters.connection_handle.npad_id, parameters.database_id_version);
2204
2205 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2206 .SetPalmaDataBaseIdentificationVersion(parameters.connection_handle,
2207 parameters.database_id_version);
2208
2209 IPC::ResponseBuilder rb{ctx, 2};
2210 rb.Push(ResultSuccess);
2211}
2212
2213void Hid::GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
2214 IPC::RequestParser rp{ctx};
2215 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2216
2217 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2218
2219 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2220 .GetPalmaDataBaseIdentificationVersion(connection_handle);
2221
2222 IPC::ResponseBuilder rb{ctx, 2};
2223 rb.Push(ResultSuccess);
2224}
2225
2226void Hid::SuspendPalmaFeature(HLERequestContext& ctx) {
2227 LOG_WARNING(Service_HID, "(STUBBED) called");
2228
2229 IPC::ResponseBuilder rb{ctx, 2};
2230 rb.Push(ResultSuccess);
2231}
2232
2233void Hid::GetPalmaOperationResult(HLERequestContext& ctx) {
2234 IPC::RequestParser rp{ctx};
2235 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2236
2237 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2238
2239 const auto result = applet_resource->GetController<Controller_Palma>(HidController::Palma)
2240 .GetPalmaOperationResult(connection_handle);
2241
2242 IPC::ResponseBuilder rb{ctx, 2};
2243 rb.Push(result);
2244}
2245
2246void Hid::ReadPalmaPlayLog(HLERequestContext& ctx) {
2247 LOG_WARNING(Service_HID, "(STUBBED) called");
2248
2249 IPC::ResponseBuilder rb{ctx, 2};
2250 rb.Push(ResultSuccess);
2251}
2252
2253void Hid::ResetPalmaPlayLog(HLERequestContext& ctx) {
2254 LOG_WARNING(Service_HID, "(STUBBED) called");
2255
2256 IPC::ResponseBuilder rb{ctx, 2};
2257 rb.Push(ResultSuccess);
2258}
2259
2260void Hid::SetIsPalmaAllConnectable(HLERequestContext& ctx) {
2261 IPC::RequestParser rp{ctx};
2262 struct Parameters {
2263 bool is_palma_all_connectable;
2264 INSERT_PADDING_BYTES_NOINIT(7);
2265 u64 applet_resource_user_id;
2266 };
2267 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2268
2269 const auto parameters{rp.PopRaw<Parameters>()};
2270
2271 LOG_WARNING(Service_HID,
2272 "(STUBBED) called, is_palma_all_connectable={},applet_resource_user_id={}",
2273 parameters.is_palma_all_connectable, parameters.applet_resource_user_id);
2274
2275 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2276 .SetIsPalmaAllConnectable(parameters.is_palma_all_connectable);
2277
2278 IPC::ResponseBuilder rb{ctx, 2};
2279 rb.Push(ResultSuccess);
2280}
2281
2282void Hid::SetIsPalmaPairedConnectable(HLERequestContext& ctx) {
2283 LOG_WARNING(Service_HID, "(STUBBED) called");
2284
2285 IPC::ResponseBuilder rb{ctx, 2};
2286 rb.Push(ResultSuccess);
2287}
2288
2289void Hid::PairPalma(HLERequestContext& ctx) {
2290 IPC::RequestParser rp{ctx};
2291 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2292
2293 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2294
2295 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2296 .PairPalma(connection_handle);
2297
2298 IPC::ResponseBuilder rb{ctx, 2};
2299 rb.Push(ResultSuccess);
2300}
2301
2302void Hid::SetPalmaBoostMode(HLERequestContext& ctx) {
2303 IPC::RequestParser rp{ctx};
2304 const auto palma_boost_mode{rp.Pop<bool>()};
2305
2306 LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode);
2307
2308 applet_resource->GetController<Controller_Palma>(HidController::Palma)
2309 .SetPalmaBoostMode(palma_boost_mode);
2310
2311 IPC::ResponseBuilder rb{ctx, 2};
2312 rb.Push(ResultSuccess);
2313}
2314
2315void Hid::CancelWritePalmaWaveEntry(HLERequestContext& ctx) {
2316 LOG_WARNING(Service_HID, "(STUBBED) called");
2317
2318 IPC::ResponseBuilder rb{ctx, 2};
2319 rb.Push(ResultSuccess);
2320}
2321
2322void Hid::EnablePalmaBoostMode(HLERequestContext& ctx) {
2323 LOG_WARNING(Service_HID, "(STUBBED) called");
2324
2325 IPC::ResponseBuilder rb{ctx, 2};
2326 rb.Push(ResultSuccess);
2327}
2328
2329void Hid::GetPalmaBluetoothAddress(HLERequestContext& ctx) {
2330 LOG_WARNING(Service_HID, "(STUBBED) called");
2331
2332 IPC::ResponseBuilder rb{ctx, 2};
2333 rb.Push(ResultSuccess);
2334}
2335
2336void Hid::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
2337 LOG_WARNING(Service_HID, "(STUBBED) called");
2338
2339 IPC::ResponseBuilder rb{ctx, 2};
2340 rb.Push(ResultSuccess);
2341}
2342
2343void Hid::SetNpadCommunicationMode(HLERequestContext& ctx) {
2344 IPC::RequestParser rp{ctx};
2345 const auto applet_resource_user_id{rp.Pop<u64>()};
2346 const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()};
2347
2348 applet_resource->GetController<Controller_NPad>(HidController::NPad)
2349 .SetNpadCommunicationMode(communication_mode);
2350
2351 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}",
2352 applet_resource_user_id, communication_mode);
2353
2354 IPC::ResponseBuilder rb{ctx, 2};
2355 rb.Push(ResultSuccess);
2356}
2357
2358void Hid::GetNpadCommunicationMode(HLERequestContext& ctx) {
2359 IPC::RequestParser rp{ctx};
2360
2361 LOG_WARNING(Service_HID, "(STUBBED) called");
2362
2363 IPC::ResponseBuilder rb{ctx, 4};
2364 rb.Push(ResultSuccess);
2365 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
2366 .GetNpadCommunicationMode());
2367}
2368
2369void Hid::SetTouchScreenConfiguration(HLERequestContext& ctx) {
2370 IPC::RequestParser rp{ctx};
2371 const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};
2372 const auto applet_resource_user_id{rp.Pop<u64>()};
2373
2374 LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}",
2375 touchscreen_mode.mode, applet_resource_user_id);
2376
2377 IPC::ResponseBuilder rb{ctx, 2};
2378 rb.Push(ResultSuccess);
2379}
2380
2381void Hid::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) {
2382 IPC::RequestParser rp{ctx};
2383 struct Parameters {
2384 s32 unknown;
2385 INSERT_PADDING_WORDS_NOINIT(1);
2386 u64 applet_resource_user_id;
2387 };
2388 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2389
2390 const auto parameters{rp.PopRaw<Parameters>()};
2391
2392 LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}",
2393 parameters.unknown, parameters.applet_resource_user_id);
2394
2395 IPC::ResponseBuilder rb{ctx, 3};
2396 rb.Push(ResultSuccess);
2397 rb.Push(false);
2398}
2399
2400class HidDbg final : public ServiceFramework<HidDbg> {
2401public:
2402 explicit HidDbg(Core::System& system_) : ServiceFramework{system_, "hid:dbg"} {
2403 // clang-format off
2404 static const FunctionInfo functions[] = {
2405 {0, nullptr, "DeactivateDebugPad"},
2406 {1, nullptr, "SetDebugPadAutoPilotState"},
2407 {2, nullptr, "UnsetDebugPadAutoPilotState"},
2408 {10, nullptr, "DeactivateTouchScreen"},
2409 {11, nullptr, "SetTouchScreenAutoPilotState"},
2410 {12, nullptr, "UnsetTouchScreenAutoPilotState"},
2411 {13, nullptr, "GetTouchScreenConfiguration"},
2412 {14, nullptr, "ProcessTouchScreenAutoTune"},
2413 {15, nullptr, "ForceStopTouchScreenManagement"},
2414 {16, nullptr, "ForceRestartTouchScreenManagement"},
2415 {17, nullptr, "IsTouchScreenManaged"},
2416 {20, nullptr, "DeactivateMouse"},
2417 {21, nullptr, "SetMouseAutoPilotState"},
2418 {22, nullptr, "UnsetMouseAutoPilotState"},
2419 {25, nullptr, "SetDebugMouseAutoPilotState"},
2420 {26, nullptr, "UnsetDebugMouseAutoPilotState"},
2421 {30, nullptr, "DeactivateKeyboard"},
2422 {31, nullptr, "SetKeyboardAutoPilotState"},
2423 {32, nullptr, "UnsetKeyboardAutoPilotState"},
2424 {50, nullptr, "DeactivateXpad"},
2425 {51, nullptr, "SetXpadAutoPilotState"},
2426 {52, nullptr, "UnsetXpadAutoPilotState"},
2427 {53, nullptr, "DeactivateJoyXpad"},
2428 {60, nullptr, "ClearNpadSystemCommonPolicy"},
2429 {61, nullptr, "DeactivateNpad"},
2430 {62, nullptr, "ForceDisconnectNpad"},
2431 {91, nullptr, "DeactivateGesture"},
2432 {110, nullptr, "DeactivateHomeButton"},
2433 {111, nullptr, "SetHomeButtonAutoPilotState"},
2434 {112, nullptr, "UnsetHomeButtonAutoPilotState"},
2435 {120, nullptr, "DeactivateSleepButton"},
2436 {121, nullptr, "SetSleepButtonAutoPilotState"},
2437 {122, nullptr, "UnsetSleepButtonAutoPilotState"},
2438 {123, nullptr, "DeactivateInputDetector"},
2439 {130, nullptr, "DeactivateCaptureButton"},
2440 {131, nullptr, "SetCaptureButtonAutoPilotState"},
2441 {132, nullptr, "UnsetCaptureButtonAutoPilotState"},
2442 {133, nullptr, "SetShiftAccelerometerCalibrationValue"},
2443 {134, nullptr, "GetShiftAccelerometerCalibrationValue"},
2444 {135, nullptr, "SetShiftGyroscopeCalibrationValue"},
2445 {136, nullptr, "GetShiftGyroscopeCalibrationValue"},
2446 {140, nullptr, "DeactivateConsoleSixAxisSensor"},
2447 {141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
2448 {142, nullptr, "DeactivateSevenSixAxisSensor"},
2449 {143, nullptr, "GetConsoleSixAxisSensorCountStates"},
2450 {144, nullptr, "GetAccelerometerFsr"},
2451 {145, nullptr, "SetAccelerometerFsr"},
2452 {146, nullptr, "GetAccelerometerOdr"},
2453 {147, nullptr, "SetAccelerometerOdr"},
2454 {148, nullptr, "GetGyroscopeFsr"},
2455 {149, nullptr, "SetGyroscopeFsr"},
2456 {150, nullptr, "GetGyroscopeOdr"},
2457 {151, nullptr, "SetGyroscopeOdr"},
2458 {152, nullptr, "GetWhoAmI"},
2459 {201, nullptr, "ActivateFirmwareUpdate"},
2460 {202, nullptr, "DeactivateFirmwareUpdate"},
2461 {203, nullptr, "StartFirmwareUpdate"},
2462 {204, nullptr, "GetFirmwareUpdateStage"},
2463 {205, nullptr, "GetFirmwareVersion"},
2464 {206, nullptr, "GetDestinationFirmwareVersion"},
2465 {207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
2466 {208, nullptr, "StartFirmwareUpdateForRevert"},
2467 {209, nullptr, "GetAvailableFirmwareVersionForRevert"},
2468 {210, nullptr, "IsFirmwareUpdatingDevice"},
2469 {211, nullptr, "StartFirmwareUpdateIndividual"},
2470 {215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
2471 {216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
2472 {221, nullptr, "UpdateControllerColor"},
2473 {222, nullptr, "ConnectUsbPadsAsync"},
2474 {223, nullptr, "DisconnectUsbPadsAsync"},
2475 {224, nullptr, "UpdateDesignInfo"},
2476 {225, nullptr, "GetUniquePadDriverState"},
2477 {226, nullptr, "GetSixAxisSensorDriverStates"},
2478 {227, nullptr, "GetRxPacketHistory"},
2479 {228, nullptr, "AcquireOperationEventHandle"},
2480 {229, nullptr, "ReadSerialFlash"},
2481 {230, nullptr, "WriteSerialFlash"},
2482 {231, nullptr, "GetOperationResult"},
2483 {232, nullptr, "EnableShipmentMode"},
2484 {233, nullptr, "ClearPairingInfo"},
2485 {234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
2486 {235, nullptr, "EnableAnalogStickPower"},
2487 {236, nullptr, "RequestKuinaUartClockCal"},
2488 {237, nullptr, "GetKuinaUartClockCal"},
2489 {238, nullptr, "SetKuinaUartClockTrim"},
2490 {239, nullptr, "KuinaLoopbackTest"},
2491 {240, nullptr, "RequestBatteryVoltage"},
2492 {241, nullptr, "GetBatteryVoltage"},
2493 {242, nullptr, "GetUniquePadPowerInfo"},
2494 {243, nullptr, "RebootUniquePad"},
2495 {244, nullptr, "RequestKuinaFirmwareVersion"},
2496 {245, nullptr, "GetKuinaFirmwareVersion"},
2497 {246, nullptr, "GetVidPid"},
2498 {247, nullptr, "GetAnalogStickCalibrationValue"},
2499 {248, nullptr, "GetUniquePadIdsFull"},
2500 {249, nullptr, "ConnectUniquePad"},
2501 {250, nullptr, "IsVirtual"},
2502 {251, nullptr, "GetAnalogStickModuleParam"},
2503 {301, nullptr, "GetAbstractedPadHandles"},
2504 {302, nullptr, "GetAbstractedPadState"},
2505 {303, nullptr, "GetAbstractedPadsState"},
2506 {321, nullptr, "SetAutoPilotVirtualPadState"},
2507 {322, nullptr, "UnsetAutoPilotVirtualPadState"},
2508 {323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
2509 {324, nullptr, "AttachHdlsWorkBuffer"},
2510 {325, nullptr, "ReleaseHdlsWorkBuffer"},
2511 {326, nullptr, "DumpHdlsNpadAssignmentState"},
2512 {327, nullptr, "DumpHdlsStates"},
2513 {328, nullptr, "ApplyHdlsNpadAssignmentState"},
2514 {329, nullptr, "ApplyHdlsStateList"},
2515 {330, nullptr, "AttachHdlsVirtualDevice"},
2516 {331, nullptr, "DetachHdlsVirtualDevice"},
2517 {332, nullptr, "SetHdlsState"},
2518 {350, nullptr, "AddRegisteredDevice"},
2519 {400, nullptr, "DisableExternalMcuOnNxDevice"},
2520 {401, nullptr, "DisableRailDeviceFiltering"},
2521 {402, nullptr, "EnableWiredPairing"},
2522 {403, nullptr, "EnableShipmentModeAutoClear"},
2523 {404, nullptr, "SetRailEnabled"},
2524 {500, nullptr, "SetFactoryInt"},
2525 {501, nullptr, "IsFactoryBootEnabled"},
2526 {550, nullptr, "SetAnalogStickModelDataTemporarily"},
2527 {551, nullptr, "GetAnalogStickModelData"},
2528 {552, nullptr, "ResetAnalogStickModelData"},
2529 {600, nullptr, "ConvertPadState"},
2530 {650, nullptr, "AddButtonPlayData"},
2531 {651, nullptr, "StartButtonPlayData"},
2532 {652, nullptr, "StopButtonPlayData"},
2533 {2000, nullptr, "DeactivateDigitizer"},
2534 {2001, nullptr, "SetDigitizerAutoPilotState"},
2535 {2002, nullptr, "UnsetDigitizerAutoPilotState"},
2536 {2002, nullptr, "ReloadFirmwareDebugSettings"},
2537 };
2538 // clang-format on
2539
2540 RegisterHandlers(functions);
2541 }
2542};
2543
2544class HidSys final : public ServiceFramework<HidSys> {
2545public:
2546 explicit HidSys(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_)
2547 : ServiceFramework{system_, "hid:sys"}, service_context{system_, "hid:sys"},
2548 applet_resource{applet_resource_} {
2549 // clang-format off
2550 static const FunctionInfo functions[] = {
2551 {31, nullptr, "SendKeyboardLockKeyEvent"},
2552 {101, nullptr, "AcquireHomeButtonEventHandle"},
2553 {111, nullptr, "ActivateHomeButton"},
2554 {121, nullptr, "AcquireSleepButtonEventHandle"},
2555 {131, nullptr, "ActivateSleepButton"},
2556 {141, nullptr, "AcquireCaptureButtonEventHandle"},
2557 {151, nullptr, "ActivateCaptureButton"},
2558 {161, nullptr, "GetPlatformConfig"},
2559 {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
2560 {211, nullptr, "GetNpadsWithNfc"},
2561 {212, nullptr, "AcquireNfcActivateEventHandle"},
2562 {213, nullptr, "ActivateNfc"},
2563 {214, nullptr, "GetXcdHandleForNpadWithNfc"},
2564 {215, nullptr, "IsNfcActivated"},
2565 {230, nullptr, "AcquireIrSensorEventHandle"},
2566 {231, nullptr, "ActivateIrSensor"},
2567 {232, nullptr, "GetIrSensorState"},
2568 {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
2569 {301, nullptr, "ActivateNpadSystem"},
2570 {303, &HidSys::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
2571 {304, nullptr, "EnableAssigningSingleOnSlSrPress"},
2572 {305, nullptr, "DisableAssigningSingleOnSlSrPress"},
2573 {306, &HidSys::GetLastActiveNpad, "GetLastActiveNpad"},
2574 {307, nullptr, "GetNpadSystemExtStyle"},
2575 {308, nullptr, "ApplyNpadSystemCommonPolicyFull"},
2576 {309, nullptr, "GetNpadFullKeyGripColor"},
2577 {310, nullptr, "GetMaskedSupportedNpadStyleSet"},
2578 {311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
2579 {312, nullptr, "SetSupportedNpadStyleSetAll"},
2580 {313, nullptr, "GetNpadCaptureButtonAssignment"},
2581 {314, nullptr, "GetAppletFooterUiType"},
2582 {315, nullptr, "GetAppletDetailedUiType"},
2583 {316, nullptr, "GetNpadInterfaceType"},
2584 {317, nullptr, "GetNpadLeftRightInterfaceType"},
2585 {318, nullptr, "HasBattery"},
2586 {319, nullptr, "HasLeftRightBattery"},
2587 {321, &HidSys::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
2588 {322, nullptr, "GetIrSensorState"},
2589 {323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
2590 {324, nullptr, "GetUniquePadButtonSet"},
2591 {325, nullptr, "GetUniquePadColor"},
2592 {326, nullptr, "GetUniquePadAppletDetailedUiType"},
2593 {327, nullptr, "GetAbstractedPadIdDataFromNpad"},
2594 {328, nullptr, "AttachAbstractedPadToNpad"},
2595 {329, nullptr, "DetachAbstractedPadAll"},
2596 {330, nullptr, "CheckAbstractedPadConnection"},
2597 {500, nullptr, "SetAppletResourceUserId"},
2598 {501, nullptr, "RegisterAppletResourceUserId"},
2599 {502, nullptr, "UnregisterAppletResourceUserId"},
2600 {503, nullptr, "EnableAppletToGetInput"},
2601 {504, nullptr, "SetAruidValidForVibration"},
2602 {505, nullptr, "EnableAppletToGetSixAxisSensor"},
2603 {506, nullptr, "EnableAppletToGetPadInput"},
2604 {507, nullptr, "EnableAppletToGetTouchScreen"},
2605 {510, nullptr, "SetVibrationMasterVolume"},
2606 {511, nullptr, "GetVibrationMasterVolume"},
2607 {512, nullptr, "BeginPermitVibrationSession"},
2608 {513, nullptr, "EndPermitVibrationSession"},
2609 {514, nullptr, "Unknown514"},
2610 {520, nullptr, "EnableHandheldHids"},
2611 {521, nullptr, "DisableHandheldHids"},
2612 {522, nullptr, "SetJoyConRailEnabled"},
2613 {523, nullptr, "IsJoyConRailEnabled"},
2614 {524, nullptr, "IsHandheldHidsEnabled"},
2615 {525, nullptr, "IsJoyConAttachedOnAllRail"},
2616 {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
2617 {541, nullptr, "GetPlayReportControllerUsages"},
2618 {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
2619 {543, nullptr, "GetRegisteredDevicesOld"},
2620 {544, nullptr, "AcquireConnectionTriggerTimeoutEvent"},
2621 {545, nullptr, "SendConnectionTrigger"},
2622 {546, nullptr, "AcquireDeviceRegisteredEventForControllerSupport"},
2623 {547, nullptr, "GetAllowedBluetoothLinksCount"},
2624 {548, nullptr, "GetRegisteredDevices"},
2625 {549, nullptr, "GetConnectableRegisteredDevices"},
2626 {700, nullptr, "ActivateUniquePad"},
2627 {702, nullptr, "AcquireUniquePadConnectionEventHandle"},
2628 {703, nullptr, "GetUniquePadIds"},
2629 {751, &HidSys::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
2630 {800, nullptr, "ListSixAxisSensorHandles"},
2631 {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
2632 {802, nullptr, "ResetSixAxisSensorCalibrationValues"},
2633 {803, nullptr, "StartSixAxisSensorUserCalibration"},
2634 {804, nullptr, "CancelSixAxisSensorUserCalibration"},
2635 {805, nullptr, "GetUniquePadBluetoothAddress"},
2636 {806, nullptr, "DisconnectUniquePad"},
2637 {807, nullptr, "GetUniquePadType"},
2638 {808, nullptr, "GetUniquePadInterface"},
2639 {809, nullptr, "GetUniquePadSerialNumber"},
2640 {810, nullptr, "GetUniquePadControllerNumber"},
2641 {811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
2642 {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
2643 {821, nullptr, "StartAnalogStickManualCalibration"},
2644 {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
2645 {823, nullptr, "CancelAnalogStickManualCalibration"},
2646 {824, nullptr, "ResetAnalogStickManualCalibration"},
2647 {825, nullptr, "GetAnalogStickState"},
2648 {826, nullptr, "GetAnalogStickManualCalibrationStage"},
2649 {827, nullptr, "IsAnalogStickButtonPressed"},
2650 {828, nullptr, "IsAnalogStickInReleasePosition"},
2651 {829, nullptr, "IsAnalogStickInCircumference"},
2652 {830, nullptr, "SetNotificationLedPattern"},
2653 {831, nullptr, "SetNotificationLedPatternWithTimeout"},
2654 {832, nullptr, "PrepareHidsForNotificationWake"},
2655 {850, &HidSys::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
2656 {851, nullptr, "EnableUsbFullKeyController"},
2657 {852, nullptr, "IsUsbConnected"},
2658 {870, nullptr, "IsHandheldButtonPressedOnConsoleMode"},
2659 {900, nullptr, "ActivateInputDetector"},
2660 {901, nullptr, "NotifyInputDetector"},
2661 {1000, nullptr, "InitializeFirmwareUpdate"},
2662 {1001, nullptr, "GetFirmwareVersion"},
2663 {1002, nullptr, "GetAvailableFirmwareVersion"},
2664 {1003, nullptr, "IsFirmwareUpdateAvailable"},
2665 {1004, nullptr, "CheckFirmwareUpdateRequired"},
2666 {1005, nullptr, "StartFirmwareUpdate"},
2667 {1006, nullptr, "AbortFirmwareUpdate"},
2668 {1007, nullptr, "GetFirmwareUpdateState"},
2669 {1008, nullptr, "ActivateAudioControl"},
2670 {1009, nullptr, "AcquireAudioControlEventHandle"},
2671 {1010, nullptr, "GetAudioControlStates"},
2672 {1011, nullptr, "DeactivateAudioControl"},
2673 {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
2674 {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
2675 {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
2676 {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
2677 {1100, nullptr, "GetHidbusSystemServiceObject"},
2678 {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
2679 {1130, nullptr, "InitializeUsbFirmwareUpdate"},
2680 {1131, nullptr, "FinalizeUsbFirmwareUpdate"},
2681 {1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
2682 {1133, nullptr, "StartUsbFirmwareUpdate"},
2683 {1134, nullptr, "GetUsbFirmwareUpdateState"},
2684 {1150, nullptr, "SetTouchScreenMagnification"},
2685 {1151, nullptr, "GetTouchScreenFirmwareVersion"},
2686 {1152, nullptr, "SetTouchScreenDefaultConfiguration"},
2687 {1153, &HidSys::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
2688 {1154, nullptr, "IsFirmwareAvailableForNotification"},
2689 {1155, nullptr, "SetForceHandheldStyleVibration"},
2690 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
2691 {1157, nullptr, "CancelConnectionTrigger"},
2692 {1200, nullptr, "IsButtonConfigSupported"},
2693 {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
2694 {1202, nullptr, "DeleteButtonConfig"},
2695 {1203, nullptr, "DeleteButtonConfigEmbedded"},
2696 {1204, nullptr, "SetButtonConfigEnabled"},
2697 {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
2698 {1206, nullptr, "IsButtonConfigEnabled"},
2699 {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
2700 {1208, nullptr, "SetButtonConfigEmbedded"},
2701 {1209, nullptr, "SetButtonConfigFull"},
2702 {1210, nullptr, "SetButtonConfigLeft"},
2703 {1211, nullptr, "SetButtonConfigRight"},
2704 {1212, nullptr, "GetButtonConfigEmbedded"},
2705 {1213, nullptr, "GetButtonConfigFull"},
2706 {1214, nullptr, "GetButtonConfigLeft"},
2707 {1215, nullptr, "GetButtonConfigRight"},
2708 {1250, nullptr, "IsCustomButtonConfigSupported"},
2709 {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
2710 {1252, nullptr, "IsDefaultButtonConfigFull"},
2711 {1253, nullptr, "IsDefaultButtonConfigLeft"},
2712 {1254, nullptr, "IsDefaultButtonConfigRight"},
2713 {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
2714 {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
2715 {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
2716 {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
2717 {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
2718 {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
2719 {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
2720 {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
2721 {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
2722 {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
2723 {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
2724 {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
2725 {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
2726 {1268, nullptr, "DeleteButtonConfigStorageFull"},
2727 {1269, nullptr, "DeleteButtonConfigStorageLeft"},
2728 {1270, nullptr, "DeleteButtonConfigStorageRight"},
2729 {1271, nullptr, "IsUsingCustomButtonConfig"},
2730 {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
2731 {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
2732 {1274, nullptr, "SetDefaultButtonConfig"},
2733 {1275, nullptr, "SetAllDefaultButtonConfig"},
2734 {1276, nullptr, "SetHidButtonConfigEmbedded"},
2735 {1277, nullptr, "SetHidButtonConfigFull"},
2736 {1278, nullptr, "SetHidButtonConfigLeft"},
2737 {1279, nullptr, "SetHidButtonConfigRight"},
2738 {1280, nullptr, "GetHidButtonConfigEmbedded"},
2739 {1281, nullptr, "GetHidButtonConfigFull"},
2740 {1282, nullptr, "GetHidButtonConfigLeft"},
2741 {1283, nullptr, "GetHidButtonConfigRight"},
2742 {1284, nullptr, "GetButtonConfigStorageEmbedded"},
2743 {1285, nullptr, "GetButtonConfigStorageFull"},
2744 {1286, nullptr, "GetButtonConfigStorageLeft"},
2745 {1287, nullptr, "GetButtonConfigStorageRight"},
2746 {1288, nullptr, "SetButtonConfigStorageEmbedded"},
2747 {1289, nullptr, "SetButtonConfigStorageFull"},
2748 {1290, nullptr, "DeleteButtonConfigStorageRight"},
2749 {1291, nullptr, "DeleteButtonConfigStorageRight"},
2750 };
2751 // clang-format on
2752
2753 RegisterHandlers(functions);
2754
2755 joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent");
2756 }
2757
2758 ~HidSys() {
2759 service_context.CloseEvent(joy_detach_event);
2760 };
2761
2762private:
2763 void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
2764 LOG_WARNING(Service_HID, "called");
2765
2766 GetAppletResource()
2767 ->GetController<Controller_NPad>(HidController::NPad)
2768 .ApplyNpadSystemCommonPolicy();
2769
2770 IPC::ResponseBuilder rb{ctx, 2};
2771 rb.Push(ResultSuccess);
2772 }
2773
2774 void GetLastActiveNpad(HLERequestContext& ctx) {
2775 LOG_DEBUG(Service_HID, "(STUBBED) called");
2776
2777 IPC::ResponseBuilder rb{ctx, 3};
2778 rb.Push(ResultSuccess);
2779 rb.PushEnum(system.HIDCore().GetLastActiveController());
2780 }
2781
2782 void GetUniquePadsFromNpad(HLERequestContext& ctx) {
2783 IPC::RequestParser rp{ctx};
2784 const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
2785
2786 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type);
2787
2788 const std::vector<Core::HID::UniquePadId> unique_pads{};
2789
2790 ctx.WriteBuffer(unique_pads);
2791
2792 IPC::ResponseBuilder rb{ctx, 3};
2793 rb.Push(ResultSuccess);
2794 rb.Push(static_cast<u32>(unique_pads.size()));
2795 }
2796
2797 void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
2798 LOG_INFO(Service_AM, "called");
2799
2800 IPC::ResponseBuilder rb{ctx, 2, 1};
2801 rb.Push(ResultSuccess);
2802 rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
2803 }
2804
2805 void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
2806 const bool is_enabled = false;
2807
2808 LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
2809
2810 IPC::ResponseBuilder rb{ctx, 3};
2811 rb.Push(ResultSuccess);
2812 rb.Push(is_enabled);
2813 }
2814
2815 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
2816 LOG_WARNING(Service_HID, "(STUBBED) called");
2817
2818 Core::HID::TouchScreenConfigurationForNx touchscreen_config{
2819 .mode = Core::HID::TouchScreenModeForNx::Finger,
2820 };
2821
2822 if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
2823 touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
2824 touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
2825 }
2826
2827 IPC::ResponseBuilder rb{ctx, 6};
2828 rb.Push(ResultSuccess);
2829 rb.PushRaw(touchscreen_config);
2830 }
2831
2832 std::shared_ptr<IAppletResource> GetAppletResource() {
2833 if (applet_resource == nullptr) {
2834 applet_resource = std::make_shared<IAppletResource>(system, service_context);
2835 }
2836
2837 return applet_resource;
2838 }
2839
2840 Kernel::KEvent* joy_detach_event;
2841 KernelHelpers::ServiceContext service_context;
2842 std::shared_ptr<IAppletResource> applet_resource;
2843};
2844
2845void LoopProcess(Core::System& system) { 17void LoopProcess(Core::System& system) {
2846 auto server_manager = std::make_unique<ServerManager>(system); 18 auto server_manager = std::make_unique<ServerManager>(system);
2847 std::shared_ptr<IAppletResource> applet_resource; 19 std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system);
20 std::shared_ptr<HidFirmwareSettings> firmware_settings =
21 std::make_shared<HidFirmwareSettings>();
22
23 server_manager->RegisterNamedService(
24 "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings));
25 server_manager->RegisterNamedService(
26 "hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager));
27 server_manager->RegisterNamedService(
28 "hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager));
2848 29
2849 server_manager->RegisterNamedService("hid", std::make_shared<Hid>(system, applet_resource));
2850 server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system)); 30 server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system));
2851 server_manager->RegisterNamedService("hid:dbg", std::make_shared<HidDbg>(system));
2852 server_manager->RegisterNamedService("hid:sys",
2853 std::make_shared<HidSys>(system, applet_resource));
2854 31
2855 server_manager->RegisterNamedService("irs", std::make_shared<Service::IRS::IRS>(system)); 32 server_manager->RegisterNamedService("irs", std::make_shared<IRS::IRS>(system));
2856 server_manager->RegisterNamedService("irs:sys", 33 server_manager->RegisterNamedService("irs:sys", std::make_shared<IRS::IRS_SYS>(system));
2857 std::make_shared<Service::IRS::IRS_SYS>(system));
2858 34
2859 server_manager->RegisterNamedService("xcd:sys", std::make_shared<XCD_SYS>(system)); 35 server_manager->RegisterNamedService("xcd:sys", std::make_shared<XCD_SYS>(system));
36
2860 system.RunServer(std::move(server_manager)); 37 system.RunServer(std::move(server_manager));
2861} 38}
2862 39
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 0ca43de93..ec5463f4e 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -3,220 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <chrono> 6namespace Core {
7 7class System;
8#include "core/hle/service/hid/controllers/controller_base.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/service.h"
11
12namespace Core::Timing {
13struct EventType;
14}
15
16namespace Service::SM {
17class ServiceManager;
18} 8}
19 9
20namespace Service::HID { 10namespace Service::HID {
21 11
22enum class HidController : std::size_t {
23 DebugPad,
24 Touchscreen,
25 Mouse,
26 Keyboard,
27 XPad,
28 HomeButton,
29 SleepButton,
30 CaptureButton,
31 InputDetector,
32 UniquePad,
33 NPad,
34 Gesture,
35 ConsoleSixAxisSensor,
36 DebugMouse,
37 Palma,
38
39 MaxControllers,
40};
41
42class IAppletResource final : public ServiceFramework<IAppletResource> {
43public:
44 explicit IAppletResource(Core::System& system_,
45 KernelHelpers::ServiceContext& service_context_);
46 ~IAppletResource() override;
47
48 void ActivateController(HidController controller);
49 void DeactivateController(HidController controller);
50
51 template <typename T>
52 T& GetController(HidController controller) {
53 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
54 }
55
56 template <typename T>
57 const T& GetController(HidController controller) const {
58 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
59 }
60
61private:
62 template <typename T>
63 void MakeController(HidController controller, u8* shared_memory) {
64 if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
65 controllers[static_cast<std::size_t>(controller)] =
66 std::make_unique<T>(system, shared_memory);
67 } else {
68 controllers[static_cast<std::size_t>(controller)] =
69 std::make_unique<T>(system.HIDCore(), shared_memory);
70 }
71 }
72
73 template <typename T>
74 void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
75 controllers[static_cast<std::size_t>(controller)] =
76 std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
77 }
78
79 void GetSharedMemoryHandle(HLERequestContext& ctx);
80 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
81 void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
82 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
83 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
84
85 KernelHelpers::ServiceContext& service_context;
86
87 std::shared_ptr<Core::Timing::EventType> npad_update_event;
88 std::shared_ptr<Core::Timing::EventType> default_update_event;
89 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
90 std::shared_ptr<Core::Timing::EventType> motion_update_event;
91
92 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
93 controllers{};
94};
95
96class Hid final : public ServiceFramework<Hid> {
97public:
98 explicit Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_);
99 ~Hid() override;
100
101 std::shared_ptr<IAppletResource> GetAppletResource();
102
103private:
104 void CreateAppletResource(HLERequestContext& ctx);
105 void ActivateDebugPad(HLERequestContext& ctx);
106 void ActivateTouchScreen(HLERequestContext& ctx);
107 void ActivateMouse(HLERequestContext& ctx);
108 void ActivateKeyboard(HLERequestContext& ctx);
109 void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
110 void ActivateXpad(HLERequestContext& ctx);
111 void GetXpadIDs(HLERequestContext& ctx);
112 void ActivateSixAxisSensor(HLERequestContext& ctx);
113 void DeactivateSixAxisSensor(HLERequestContext& ctx);
114 void StartSixAxisSensor(HLERequestContext& ctx);
115 void StopSixAxisSensor(HLERequestContext& ctx);
116 void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
117 void EnableSixAxisSensorFusion(HLERequestContext& ctx);
118 void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
119 void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
120 void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
121 void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
122 void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
123 void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
124 void IsSixAxisSensorAtRest(HLERequestContext& ctx);
125 void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
126 void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
127 void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
128 void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
129 void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
130 void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
131 void ActivateGesture(HLERequestContext& ctx);
132 void SetSupportedNpadStyleSet(HLERequestContext& ctx);
133 void GetSupportedNpadStyleSet(HLERequestContext& ctx);
134 void SetSupportedNpadIdType(HLERequestContext& ctx);
135 void ActivateNpad(HLERequestContext& ctx);
136 void DeactivateNpad(HLERequestContext& ctx);
137 void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
138 void DisconnectNpad(HLERequestContext& ctx);
139 void GetPlayerLedPattern(HLERequestContext& ctx);
140 void ActivateNpadWithRevision(HLERequestContext& ctx);
141 void SetNpadJoyHoldType(HLERequestContext& ctx);
142 void GetNpadJoyHoldType(HLERequestContext& ctx);
143 void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
144 void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
145 void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
146 void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
147 void StartLrAssignmentMode(HLERequestContext& ctx);
148 void StopLrAssignmentMode(HLERequestContext& ctx);
149 void SetNpadHandheldActivationMode(HLERequestContext& ctx);
150 void GetNpadHandheldActivationMode(HLERequestContext& ctx);
151 void SwapNpadAssignment(HLERequestContext& ctx);
152 void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
153 void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
154 void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
155 void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
156 void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
157 void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
158 void GetVibrationDeviceInfo(HLERequestContext& ctx);
159 void SendVibrationValue(HLERequestContext& ctx);
160 void GetActualVibrationValue(HLERequestContext& ctx);
161 void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
162 void PermitVibration(HLERequestContext& ctx);
163 void IsVibrationPermitted(HLERequestContext& ctx);
164 void SendVibrationValues(HLERequestContext& ctx);
165 void SendVibrationGcErmCommand(HLERequestContext& ctx);
166 void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
167 void BeginPermitVibrationSession(HLERequestContext& ctx);
168 void EndPermitVibrationSession(HLERequestContext& ctx);
169 void IsVibrationDeviceMounted(HLERequestContext& ctx);
170 void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
171 void StartConsoleSixAxisSensor(HLERequestContext& ctx);
172 void StopConsoleSixAxisSensor(HLERequestContext& ctx);
173 void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
174 void StartSevenSixAxisSensor(HLERequestContext& ctx);
175 void StopSevenSixAxisSensor(HLERequestContext& ctx);
176 void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
177 void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
178 void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
179 void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
180 void GetPalmaConnectionHandle(HLERequestContext& ctx);
181 void InitializePalma(HLERequestContext& ctx);
182 void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
183 void GetPalmaOperationInfo(HLERequestContext& ctx);
184 void PlayPalmaActivity(HLERequestContext& ctx);
185 void SetPalmaFrModeType(HLERequestContext& ctx);
186 void ReadPalmaStep(HLERequestContext& ctx);
187 void EnablePalmaStep(HLERequestContext& ctx);
188 void ResetPalmaStep(HLERequestContext& ctx);
189 void ReadPalmaApplicationSection(HLERequestContext& ctx);
190 void WritePalmaApplicationSection(HLERequestContext& ctx);
191 void ReadPalmaUniqueCode(HLERequestContext& ctx);
192 void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
193 void WritePalmaActivityEntry(HLERequestContext& ctx);
194 void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
195 void WritePalmaWaveEntry(HLERequestContext& ctx);
196 void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
197 void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
198 void SuspendPalmaFeature(HLERequestContext& ctx);
199 void GetPalmaOperationResult(HLERequestContext& ctx);
200 void ReadPalmaPlayLog(HLERequestContext& ctx);
201 void ResetPalmaPlayLog(HLERequestContext& ctx);
202 void SetIsPalmaAllConnectable(HLERequestContext& ctx);
203 void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
204 void PairPalma(HLERequestContext& ctx);
205 void SetPalmaBoostMode(HLERequestContext& ctx);
206 void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
207 void EnablePalmaBoostMode(HLERequestContext& ctx);
208 void GetPalmaBluetoothAddress(HLERequestContext& ctx);
209 void SetDisallowedPalmaConnection(HLERequestContext& ctx);
210 void SetNpadCommunicationMode(HLERequestContext& ctx);
211 void GetNpadCommunicationMode(HLERequestContext& ctx);
212 void SetTouchScreenConfiguration(HLERequestContext& ctx);
213 void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
214
215 std::shared_ptr<IAppletResource> applet_resource;
216
217 KernelHelpers::ServiceContext service_context;
218};
219
220void LoopProcess(Core::System& system); 12void LoopProcess(Core::System& system);
221 13
222} // namespace Service::HID 14} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_debug_server.cpp b/src/core/hle/service/hid/hid_debug_server.cpp
new file mode 100644
index 000000000..6294f3dfb
--- /dev/null
+++ b/src/core/hle/service/hid/hid_debug_server.cpp
@@ -0,0 +1,159 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/hid/hid_debug_server.h"
5#include "core/hle/service/hid/resource_manager.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::HID {
9
10IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
11 : ServiceFramework{system_, "hid:dbg"}, resource_manager{resource} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, nullptr, "DeactivateDebugPad"},
15 {1, nullptr, "SetDebugPadAutoPilotState"},
16 {2, nullptr, "UnsetDebugPadAutoPilotState"},
17 {10, nullptr, "DeactivateTouchScreen"},
18 {11, nullptr, "SetTouchScreenAutoPilotState"},
19 {12, nullptr, "UnsetTouchScreenAutoPilotState"},
20 {13, nullptr, "GetTouchScreenConfiguration"},
21 {14, nullptr, "ProcessTouchScreenAutoTune"},
22 {15, nullptr, "ForceStopTouchScreenManagement"},
23 {16, nullptr, "ForceRestartTouchScreenManagement"},
24 {17, nullptr, "IsTouchScreenManaged"},
25 {20, nullptr, "DeactivateMouse"},
26 {21, nullptr, "SetMouseAutoPilotState"},
27 {22, nullptr, "UnsetMouseAutoPilotState"},
28 {25, nullptr, "SetDebugMouseAutoPilotState"},
29 {26, nullptr, "UnsetDebugMouseAutoPilotState"},
30 {30, nullptr, "DeactivateKeyboard"},
31 {31, nullptr, "SetKeyboardAutoPilotState"},
32 {32, nullptr, "UnsetKeyboardAutoPilotState"},
33 {50, nullptr, "DeactivateXpad"},
34 {51, nullptr, "SetXpadAutoPilotState"},
35 {52, nullptr, "UnsetXpadAutoPilotState"},
36 {53, nullptr, "DeactivateJoyXpad"},
37 {60, nullptr, "ClearNpadSystemCommonPolicy"},
38 {61, nullptr, "DeactivateNpad"},
39 {62, nullptr, "ForceDisconnectNpad"},
40 {91, nullptr, "DeactivateGesture"},
41 {110, nullptr, "DeactivateHomeButton"},
42 {111, nullptr, "SetHomeButtonAutoPilotState"},
43 {112, nullptr, "UnsetHomeButtonAutoPilotState"},
44 {120, nullptr, "DeactivateSleepButton"},
45 {121, nullptr, "SetSleepButtonAutoPilotState"},
46 {122, nullptr, "UnsetSleepButtonAutoPilotState"},
47 {123, nullptr, "DeactivateInputDetector"},
48 {130, nullptr, "DeactivateCaptureButton"},
49 {131, nullptr, "SetCaptureButtonAutoPilotState"},
50 {132, nullptr, "UnsetCaptureButtonAutoPilotState"},
51 {133, nullptr, "SetShiftAccelerometerCalibrationValue"},
52 {134, nullptr, "GetShiftAccelerometerCalibrationValue"},
53 {135, nullptr, "SetShiftGyroscopeCalibrationValue"},
54 {136, nullptr, "GetShiftGyroscopeCalibrationValue"},
55 {140, nullptr, "DeactivateConsoleSixAxisSensor"},
56 {141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
57 {142, nullptr, "DeactivateSevenSixAxisSensor"},
58 {143, nullptr, "GetConsoleSixAxisSensorCountStates"},
59 {144, nullptr, "GetAccelerometerFsr"},
60 {145, nullptr, "SetAccelerometerFsr"},
61 {146, nullptr, "GetAccelerometerOdr"},
62 {147, nullptr, "SetAccelerometerOdr"},
63 {148, nullptr, "GetGyroscopeFsr"},
64 {149, nullptr, "SetGyroscopeFsr"},
65 {150, nullptr, "GetGyroscopeOdr"},
66 {151, nullptr, "SetGyroscopeOdr"},
67 {152, nullptr, "GetWhoAmI"},
68 {201, nullptr, "ActivateFirmwareUpdate"},
69 {202, nullptr, "DeactivateFirmwareUpdate"},
70 {203, nullptr, "StartFirmwareUpdate"},
71 {204, nullptr, "GetFirmwareUpdateStage"},
72 {205, nullptr, "GetFirmwareVersion"},
73 {206, nullptr, "GetDestinationFirmwareVersion"},
74 {207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
75 {208, nullptr, "StartFirmwareUpdateForRevert"},
76 {209, nullptr, "GetAvailableFirmwareVersionForRevert"},
77 {210, nullptr, "IsFirmwareUpdatingDevice"},
78 {211, nullptr, "StartFirmwareUpdateIndividual"},
79 {215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
80 {216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
81 {221, nullptr, "UpdateControllerColor"},
82 {222, nullptr, "ConnectUsbPadsAsync"},
83 {223, nullptr, "DisconnectUsbPadsAsync"},
84 {224, nullptr, "UpdateDesignInfo"},
85 {225, nullptr, "GetUniquePadDriverState"},
86 {226, nullptr, "GetSixAxisSensorDriverStates"},
87 {227, nullptr, "GetRxPacketHistory"},
88 {228, nullptr, "AcquireOperationEventHandle"},
89 {229, nullptr, "ReadSerialFlash"},
90 {230, nullptr, "WriteSerialFlash"},
91 {231, nullptr, "GetOperationResult"},
92 {232, nullptr, "EnableShipmentMode"},
93 {233, nullptr, "ClearPairingInfo"},
94 {234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
95 {235, nullptr, "EnableAnalogStickPower"},
96 {236, nullptr, "RequestKuinaUartClockCal"},
97 {237, nullptr, "GetKuinaUartClockCal"},
98 {238, nullptr, "SetKuinaUartClockTrim"},
99 {239, nullptr, "KuinaLoopbackTest"},
100 {240, nullptr, "RequestBatteryVoltage"},
101 {241, nullptr, "GetBatteryVoltage"},
102 {242, nullptr, "GetUniquePadPowerInfo"},
103 {243, nullptr, "RebootUniquePad"},
104 {244, nullptr, "RequestKuinaFirmwareVersion"},
105 {245, nullptr, "GetKuinaFirmwareVersion"},
106 {246, nullptr, "GetVidPid"},
107 {247, nullptr, "GetAnalogStickCalibrationValue"},
108 {248, nullptr, "GetUniquePadIdsFull"},
109 {249, nullptr, "ConnectUniquePad"},
110 {250, nullptr, "IsVirtual"},
111 {251, nullptr, "GetAnalogStickModuleParam"},
112 {301, nullptr, "GetAbstractedPadHandles"},
113 {302, nullptr, "GetAbstractedPadState"},
114 {303, nullptr, "GetAbstractedPadsState"},
115 {321, nullptr, "SetAutoPilotVirtualPadState"},
116 {322, nullptr, "UnsetAutoPilotVirtualPadState"},
117 {323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
118 {324, nullptr, "AttachHdlsWorkBuffer"},
119 {325, nullptr, "ReleaseHdlsWorkBuffer"},
120 {326, nullptr, "DumpHdlsNpadAssignmentState"},
121 {327, nullptr, "DumpHdlsStates"},
122 {328, nullptr, "ApplyHdlsNpadAssignmentState"},
123 {329, nullptr, "ApplyHdlsStateList"},
124 {330, nullptr, "AttachHdlsVirtualDevice"},
125 {331, nullptr, "DetachHdlsVirtualDevice"},
126 {332, nullptr, "SetHdlsState"},
127 {350, nullptr, "AddRegisteredDevice"},
128 {400, nullptr, "DisableExternalMcuOnNxDevice"},
129 {401, nullptr, "DisableRailDeviceFiltering"},
130 {402, nullptr, "EnableWiredPairing"},
131 {403, nullptr, "EnableShipmentModeAutoClear"},
132 {404, nullptr, "SetRailEnabled"},
133 {500, nullptr, "SetFactoryInt"},
134 {501, nullptr, "IsFactoryBootEnabled"},
135 {550, nullptr, "SetAnalogStickModelDataTemporarily"},
136 {551, nullptr, "GetAnalogStickModelData"},
137 {552, nullptr, "ResetAnalogStickModelData"},
138 {600, nullptr, "ConvertPadState"},
139 {650, nullptr, "AddButtonPlayData"},
140 {651, nullptr, "StartButtonPlayData"},
141 {652, nullptr, "StopButtonPlayData"},
142 {2000, nullptr, "DeactivateDigitizer"},
143 {2001, nullptr, "SetDigitizerAutoPilotState"},
144 {2002, nullptr, "UnsetDigitizerAutoPilotState"},
145 {2002, nullptr, "ReloadFirmwareDebugSettings"},
146 };
147 // clang-format on
148
149 RegisterHandlers(functions);
150}
151
152IHidDebugServer::~IHidDebugServer() = default;
153
154std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
155 resource_manager->Initialize();
156 return resource_manager;
157}
158
159} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_debug_server.h b/src/core/hle/service/hid/hid_debug_server.h
new file mode 100644
index 000000000..406db2211
--- /dev/null
+++ b/src/core/hle/service/hid/hid_debug_server.h
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Core {
9class System;
10}
11
12namespace Service::HID {
13class ResourceManager;
14
15class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {
16public:
17 explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
18 ~IHidDebugServer() override;
19
20private:
21 std::shared_ptr<ResourceManager> GetResourceManager();
22
23 std::shared_ptr<ResourceManager> resource_manager;
24};
25
26} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_firmware_settings.cpp b/src/core/hle/service/hid/hid_firmware_settings.cpp
new file mode 100644
index 000000000..59bd6825c
--- /dev/null
+++ b/src/core/hle/service/hid/hid_firmware_settings.cpp
@@ -0,0 +1,99 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/hid/hid_firmware_settings.h"
5
6namespace Service::HID {
7
8HidFirmwareSettings::HidFirmwareSettings() {
9 LoadSettings(true);
10}
11
12void HidFirmwareSettings::Reload() {
13 LoadSettings(true);
14}
15
16void HidFirmwareSettings::LoadSettings(bool reload_config) {
17 if (is_initalized && !reload_config) {
18 return;
19 }
20
21 // TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values
22
23 is_debug_pad_enabled = true;
24 is_device_managed = true;
25 is_touch_i2c_managed = is_device_managed;
26 is_future_devices_emulated = false;
27 is_mcu_hardware_error_emulated = false;
28 is_rail_enabled = true;
29 is_firmware_update_failure_emulated = false;
30 is_firmware_update_failure = {};
31 is_ble_disabled = false;
32 is_dscale_disabled = false;
33 is_handheld_forced = true;
34 features_per_id_disabled = {};
35 is_touch_firmware_auto_update_disabled = false;
36 is_initalized = true;
37}
38
39bool HidFirmwareSettings::IsDebugPadEnabled() {
40 LoadSettings(false);
41 return is_debug_pad_enabled;
42}
43
44bool HidFirmwareSettings::IsDeviceManaged() {
45 LoadSettings(false);
46 return is_device_managed;
47}
48
49bool HidFirmwareSettings::IsEmulateFutureDevice() {
50 LoadSettings(false);
51 return is_future_devices_emulated;
52}
53
54bool HidFirmwareSettings::IsTouchI2cManaged() {
55 LoadSettings(false);
56 return is_touch_i2c_managed;
57}
58
59bool HidFirmwareSettings::IsHandheldForced() {
60 LoadSettings(false);
61 return is_handheld_forced;
62}
63
64bool HidFirmwareSettings::IsRailEnabled() {
65 LoadSettings(false);
66 return is_rail_enabled;
67}
68
69bool HidFirmwareSettings::IsHardwareErrorEmulated() {
70 LoadSettings(false);
71 return is_mcu_hardware_error_emulated;
72}
73
74bool HidFirmwareSettings::IsBleDisabled() {
75 LoadSettings(false);
76 return is_ble_disabled;
77}
78
79bool HidFirmwareSettings::IsDscaleDisabled() {
80 LoadSettings(false);
81 return is_dscale_disabled;
82}
83
84bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() {
85 LoadSettings(false);
86 return is_touch_firmware_auto_update_disabled;
87}
88
89HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() {
90 LoadSettings(false);
91 return is_firmware_update_failure;
92}
93
94HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() {
95 LoadSettings(false);
96 return features_per_id_disabled;
97}
98
99} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_firmware_settings.h b/src/core/hle/service/hid/hid_firmware_settings.h
new file mode 100644
index 000000000..6c10c440b
--- /dev/null
+++ b/src/core/hle/service/hid/hid_firmware_settings.h
@@ -0,0 +1,54 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::HID {
9
10/// Loads firmware config from nn::settings::fwdbg
11class HidFirmwareSettings {
12public:
13 using FirmwareSetting = std::array<u8, 4>;
14 using FeaturesPerId = std::array<bool, 0xA8>;
15
16 HidFirmwareSettings();
17
18 void Reload();
19 void LoadSettings(bool reload_config);
20
21 bool IsDebugPadEnabled();
22 bool IsDeviceManaged();
23 bool IsEmulateFutureDevice();
24 bool IsTouchI2cManaged();
25 bool IsHandheldForced();
26 bool IsRailEnabled();
27 bool IsHardwareErrorEmulated();
28 bool IsBleDisabled();
29 bool IsDscaleDisabled();
30 bool IsTouchAutoUpdateDisabled();
31
32 FirmwareSetting GetFirmwareUpdateFailure();
33 FeaturesPerId FeaturesDisabledPerId();
34
35private:
36 bool is_initalized{};
37
38 // Debug settings
39 bool is_debug_pad_enabled{};
40 bool is_device_managed{};
41 bool is_touch_i2c_managed{};
42 bool is_future_devices_emulated{};
43 bool is_mcu_hardware_error_emulated{};
44 bool is_rail_enabled{};
45 bool is_firmware_update_failure_emulated{};
46 bool is_ble_disabled{};
47 bool is_dscale_disabled{};
48 bool is_handheld_forced{};
49 bool is_touch_firmware_auto_update_disabled{};
50 FirmwareSetting is_firmware_update_failure{};
51 FeaturesPerId features_per_id_disabled{};
52};
53
54} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
new file mode 100644
index 000000000..0be6a7186
--- /dev/null
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -0,0 +1,2440 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <array>
5#include "common/common_types.h"
6#include "common/logging/log.h"
7#include "common/settings.h"
8#include "core/hid/hid_core.h"
9#include "core/hle/kernel/k_shared_memory.h"
10#include "core/hle/kernel/k_transfer_memory.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/service/hid/errors.h"
13#include "core/hle/service/hid/hid_firmware_settings.h"
14#include "core/hle/service/hid/hid_server.h"
15#include "core/hle/service/hid/resource_manager.h"
16#include "core/hle/service/ipc_helpers.h"
17#include "core/memory.h"
18
19#include "core/hle/service/hid/controllers/console_sixaxis.h"
20#include "core/hle/service/hid/controllers/controller_base.h"
21#include "core/hle/service/hid/controllers/debug_pad.h"
22#include "core/hle/service/hid/controllers/gesture.h"
23#include "core/hle/service/hid/controllers/keyboard.h"
24#include "core/hle/service/hid/controllers/mouse.h"
25#include "core/hle/service/hid/controllers/npad.h"
26#include "core/hle/service/hid/controllers/palma.h"
27#include "core/hle/service/hid/controllers/stubbed.h"
28#include "core/hle/service/hid/controllers/touchscreen.h"
29#include "core/hle/service/hid/controllers/xpad.h"
30
31namespace Service::HID {
32
33class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
34public:
35 explicit IActiveVibrationDeviceList(Core::System& system_,
36 std::shared_ptr<ResourceManager> resource)
37 : ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) {
38 // clang-format off
39 static const FunctionInfo functions[] = {
40 {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
41 };
42 // clang-format on
43
44 RegisterHandlers(functions);
45 }
46
47private:
48 void InitializeVibrationDevice(HLERequestContext& ctx) {
49 IPC::RequestParser rp{ctx};
50 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
51
52 if (resource_manager != nullptr) {
53 resource_manager->GetController<Controller_NPad>(HidController::NPad)
54 .InitializeVibrationDevice(vibration_device_handle);
55 }
56
57 LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
58 vibration_device_handle.npad_type, vibration_device_handle.npad_id,
59 vibration_device_handle.device_index);
60
61 IPC::ResponseBuilder rb{ctx, 2};
62 rb.Push(ResultSuccess);
63 }
64
65 std::shared_ptr<ResourceManager> resource_manager;
66};
67
68IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
69 std::shared_ptr<HidFirmwareSettings> settings)
70 : ServiceFramework{system_, "hid"}, resource_manager{resource}, firmware_settings{settings} {
71 // clang-format off
72 static const FunctionInfo functions[] = {
73 {0, &IHidServer::CreateAppletResource, "CreateAppletResource"},
74 {1, &IHidServer::ActivateDebugPad, "ActivateDebugPad"},
75 {11, &IHidServer::ActivateTouchScreen, "ActivateTouchScreen"},
76 {21, &IHidServer::ActivateMouse, "ActivateMouse"},
77 {26, nullptr, "ActivateDebugMouse"},
78 {31, &IHidServer::ActivateKeyboard, "ActivateKeyboard"},
79 {32, &IHidServer::SendKeyboardLockKeyEvent, "SendKeyboardLockKeyEvent"},
80 {40, &IHidServer::AcquireXpadIdEventHandle, "AcquireXpadIdEventHandle"},
81 {41, &IHidServer::ReleaseXpadIdEventHandle, "ReleaseXpadIdEventHandle"},
82 {51, &IHidServer::ActivateXpad, "ActivateXpad"},
83 {55, &IHidServer::GetXpadIds, "GetXpadIds"},
84 {56, &IHidServer::ActivateJoyXpad, "ActivateJoyXpad"},
85 {58, &IHidServer::GetJoyXpadLifoHandle, "GetJoyXpadLifoHandle"},
86 {59, &IHidServer::GetJoyXpadIds, "GetJoyXpadIds"},
87 {60, &IHidServer::ActivateSixAxisSensor, "ActivateSixAxisSensor"},
88 {61, &IHidServer::DeactivateSixAxisSensor, "DeactivateSixAxisSensor"},
89 {62, &IHidServer::GetSixAxisSensorLifoHandle, "GetSixAxisSensorLifoHandle"},
90 {63, &IHidServer::ActivateJoySixAxisSensor, "ActivateJoySixAxisSensor"},
91 {64, &IHidServer::DeactivateJoySixAxisSensor, "DeactivateJoySixAxisSensor"},
92 {65, &IHidServer::GetJoySixAxisSensorLifoHandle, "GetJoySixAxisSensorLifoHandle"},
93 {66, &IHidServer::StartSixAxisSensor, "StartSixAxisSensor"},
94 {67, &IHidServer::StopSixAxisSensor, "StopSixAxisSensor"},
95 {68, &IHidServer::IsSixAxisSensorFusionEnabled, "IsSixAxisSensorFusionEnabled"},
96 {69, &IHidServer::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"},
97 {70, &IHidServer::SetSixAxisSensorFusionParameters, "SetSixAxisSensorFusionParameters"},
98 {71, &IHidServer::GetSixAxisSensorFusionParameters, "GetSixAxisSensorFusionParameters"},
99 {72, &IHidServer::ResetSixAxisSensorFusionParameters, "ResetSixAxisSensorFusionParameters"},
100 {73, nullptr, "SetAccelerometerParameters"},
101 {74, nullptr, "GetAccelerometerParameters"},
102 {75, nullptr, "ResetAccelerometerParameters"},
103 {76, nullptr, "SetAccelerometerPlayMode"},
104 {77, nullptr, "GetAccelerometerPlayMode"},
105 {78, nullptr, "ResetAccelerometerPlayMode"},
106 {79, &IHidServer::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
107 {80, &IHidServer::GetGyroscopeZeroDriftMode, "GetGyroscopeZeroDriftMode"},
108 {81, &IHidServer::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"},
109 {82, &IHidServer::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
110 {83, &IHidServer::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"},
111 {84, &IHidServer::EnableSixAxisSensorUnalteredPassthrough, "EnableSixAxisSensorUnalteredPassthrough"},
112 {85, &IHidServer::IsSixAxisSensorUnalteredPassthroughEnabled, "IsSixAxisSensorUnalteredPassthroughEnabled"},
113 {86, nullptr, "StoreSixAxisSensorCalibrationParameter"},
114 {87, &IHidServer::LoadSixAxisSensorCalibrationParameter, "LoadSixAxisSensorCalibrationParameter"},
115 {88, &IHidServer::GetSixAxisSensorIcInformation, "GetSixAxisSensorIcInformation"},
116 {89, &IHidServer::ResetIsSixAxisSensorDeviceNewlyAssigned, "ResetIsSixAxisSensorDeviceNewlyAssigned"},
117 {91, &IHidServer::ActivateGesture, "ActivateGesture"},
118 {100, &IHidServer::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
119 {101, &IHidServer::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
120 {102, &IHidServer::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
121 {103, &IHidServer::ActivateNpad, "ActivateNpad"},
122 {104, &IHidServer::DeactivateNpad, "DeactivateNpad"},
123 {106, &IHidServer::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
124 {107, &IHidServer::DisconnectNpad, "DisconnectNpad"},
125 {108, &IHidServer::GetPlayerLedPattern, "GetPlayerLedPattern"},
126 {109, &IHidServer::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
127 {120, &IHidServer::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
128 {121, &IHidServer::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
129 {122, &IHidServer::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
130 {123, &IHidServer::SetNpadJoyAssignmentModeSingle, "SetNpadJoyAssignmentModeSingle"},
131 {124, &IHidServer::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
132 {125, &IHidServer::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
133 {126, &IHidServer::StartLrAssignmentMode, "StartLrAssignmentMode"},
134 {127, &IHidServer::StopLrAssignmentMode, "StopLrAssignmentMode"},
135 {128, &IHidServer::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
136 {129, &IHidServer::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"},
137 {130, &IHidServer::SwapNpadAssignment, "SwapNpadAssignment"},
138 {131, &IHidServer::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
139 {132, &IHidServer::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
140 {133, &IHidServer::SetNpadJoyAssignmentModeSingleWithDestination, "SetNpadJoyAssignmentModeSingleWithDestination"},
141 {134, &IHidServer::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
142 {135, &IHidServer::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"},
143 {136, &IHidServer::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"},
144 {200, &IHidServer::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
145 {201, &IHidServer::SendVibrationValue, "SendVibrationValue"},
146 {202, &IHidServer::GetActualVibrationValue, "GetActualVibrationValue"},
147 {203, &IHidServer::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
148 {204, &IHidServer::PermitVibration, "PermitVibration"},
149 {205, &IHidServer::IsVibrationPermitted, "IsVibrationPermitted"},
150 {206, &IHidServer::SendVibrationValues, "SendVibrationValues"},
151 {207, &IHidServer::SendVibrationGcErmCommand, "SendVibrationGcErmCommand"},
152 {208, &IHidServer::GetActualVibrationGcErmCommand, "GetActualVibrationGcErmCommand"},
153 {209, &IHidServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
154 {210, &IHidServer::EndPermitVibrationSession, "EndPermitVibrationSession"},
155 {211, &IHidServer::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
156 {212, nullptr, "SendVibrationValueInBool"},
157 {300, &IHidServer::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
158 {301, &IHidServer::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
159 {302, &IHidServer::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
160 {303, &IHidServer::ActivateSevenSixAxisSensor, "ActivateSevenSixAxisSensor"},
161 {304, &IHidServer::StartSevenSixAxisSensor, "StartSevenSixAxisSensor"},
162 {305, &IHidServer::StopSevenSixAxisSensor, "StopSevenSixAxisSensor"},
163 {306, &IHidServer::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"},
164 {307, &IHidServer::FinalizeSevenSixAxisSensor, "FinalizeSevenSixAxisSensor"},
165 {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
166 {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
167 {310, &IHidServer::ResetSevenSixAxisSensorTimestamp, "ResetSevenSixAxisSensorTimestamp"},
168 {400, &IHidServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
169 {401, nullptr, "EnableUsbFullKeyController"},
170 {402, nullptr, "IsUsbFullKeyControllerConnected"},
171 {403, nullptr, "HasBattery"},
172 {404, nullptr, "HasLeftRightBattery"},
173 {405, nullptr, "GetNpadInterfaceType"},
174 {406, nullptr, "GetNpadLeftRightInterfaceType"},
175 {407, nullptr, "GetNpadOfHighestBatteryLevel"},
176 {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
177 {500, &IHidServer::GetPalmaConnectionHandle, "GetPalmaConnectionHandle"},
178 {501, &IHidServer::InitializePalma, "InitializePalma"},
179 {502, &IHidServer::AcquirePalmaOperationCompleteEvent, "AcquirePalmaOperationCompleteEvent"},
180 {503, &IHidServer::GetPalmaOperationInfo, "GetPalmaOperationInfo"},
181 {504, &IHidServer::PlayPalmaActivity, "PlayPalmaActivity"},
182 {505, &IHidServer::SetPalmaFrModeType, "SetPalmaFrModeType"},
183 {506, &IHidServer::ReadPalmaStep, "ReadPalmaStep"},
184 {507, &IHidServer::EnablePalmaStep, "EnablePalmaStep"},
185 {508, &IHidServer::ResetPalmaStep, "ResetPalmaStep"},
186 {509, &IHidServer::ReadPalmaApplicationSection, "ReadPalmaApplicationSection"},
187 {510, &IHidServer::WritePalmaApplicationSection, "WritePalmaApplicationSection"},
188 {511, &IHidServer::ReadPalmaUniqueCode, "ReadPalmaUniqueCode"},
189 {512, &IHidServer::SetPalmaUniqueCodeInvalid, "SetPalmaUniqueCodeInvalid"},
190 {513, &IHidServer::WritePalmaActivityEntry, "WritePalmaActivityEntry"},
191 {514, &IHidServer::WritePalmaRgbLedPatternEntry, "WritePalmaRgbLedPatternEntry"},
192 {515, &IHidServer::WritePalmaWaveEntry, "WritePalmaWaveEntry"},
193 {516, &IHidServer::SetPalmaDataBaseIdentificationVersion, "SetPalmaDataBaseIdentificationVersion"},
194 {517, &IHidServer::GetPalmaDataBaseIdentificationVersion, "GetPalmaDataBaseIdentificationVersion"},
195 {518, &IHidServer::SuspendPalmaFeature, "SuspendPalmaFeature"},
196 {519, &IHidServer::GetPalmaOperationResult, "GetPalmaOperationResult"},
197 {520, &IHidServer::ReadPalmaPlayLog, "ReadPalmaPlayLog"},
198 {521, &IHidServer::ResetPalmaPlayLog, "ResetPalmaPlayLog"},
199 {522, &IHidServer::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
200 {523, &IHidServer::SetIsPalmaPairedConnectable, "SetIsPalmaPairedConnectable"},
201 {524, &IHidServer::PairPalma, "PairPalma"},
202 {525, &IHidServer::SetPalmaBoostMode, "SetPalmaBoostMode"},
203 {526, &IHidServer::CancelWritePalmaWaveEntry, "CancelWritePalmaWaveEntry"},
204 {527, &IHidServer::EnablePalmaBoostMode, "EnablePalmaBoostMode"},
205 {528, &IHidServer::GetPalmaBluetoothAddress, "GetPalmaBluetoothAddress"},
206 {529, &IHidServer::SetDisallowedPalmaConnection, "SetDisallowedPalmaConnection"},
207 {1000, &IHidServer::SetNpadCommunicationMode, "SetNpadCommunicationMode"},
208 {1001, &IHidServer::GetNpadCommunicationMode, "GetNpadCommunicationMode"},
209 {1002, &IHidServer::SetTouchScreenConfiguration, "SetTouchScreenConfiguration"},
210 {1003, &IHidServer::IsFirmwareUpdateNeededForNotification, "IsFirmwareUpdateNeededForNotification"},
211 {2000, nullptr, "ActivateDigitizer"},
212 };
213 // clang-format on
214
215 RegisterHandlers(functions);
216}
217
218IHidServer::~IHidServer() = default;
219
220void IHidServer::CreateAppletResource(HLERequestContext& ctx) {
221 IPC::RequestParser rp{ctx};
222 const auto applet_resource_user_id{rp.Pop<u64>()};
223
224 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
225
226 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
227 rb.Push(ResultSuccess);
228 rb.PushIpcInterface<IAppletResource>(system, resource_manager);
229}
230
231void IHidServer::ActivateDebugPad(HLERequestContext& ctx) {
232 IPC::RequestParser rp{ctx};
233 const auto applet_resource_user_id{rp.Pop<u64>()};
234
235 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
236
237 Result result = ResultSuccess;
238 auto& debug_pad =
239 GetResourceManager()->GetController<Controller_DebugPad>(HidController::DebugPad);
240
241 if (!firmware_settings->IsDeviceManaged()) {
242 result = debug_pad.Activate();
243 }
244
245 if (result.IsSuccess()) {
246 result = debug_pad.Activate(applet_resource_user_id);
247 }
248
249 IPC::ResponseBuilder rb{ctx, 2};
250 rb.Push(result);
251}
252
253void IHidServer::ActivateTouchScreen(HLERequestContext& ctx) {
254 IPC::RequestParser rp{ctx};
255 const auto applet_resource_user_id{rp.Pop<u64>()};
256
257 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
258
259 Result result = ResultSuccess;
260 auto& touch_screen =
261 GetResourceManager()->GetController<Controller_Touchscreen>(HidController::Touchscreen);
262
263 if (!firmware_settings->IsDeviceManaged()) {
264 result = touch_screen.Activate();
265 }
266
267 if (result.IsSuccess()) {
268 result = touch_screen.Activate(applet_resource_user_id);
269 }
270
271 IPC::ResponseBuilder rb{ctx, 2};
272 rb.Push(result);
273}
274
275void IHidServer::ActivateMouse(HLERequestContext& ctx) {
276 IPC::RequestParser rp{ctx};
277 const auto applet_resource_user_id{rp.Pop<u64>()};
278
279 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
280
281 Result result = ResultSuccess;
282 auto& mouse = GetResourceManager()->GetController<Controller_Mouse>(HidController::Mouse);
283
284 if (!firmware_settings->IsDeviceManaged()) {
285 result = mouse.Activate();
286 }
287
288 if (result.IsSuccess()) {
289 result = mouse.Activate(applet_resource_user_id);
290 }
291
292 IPC::ResponseBuilder rb{ctx, 2};
293 rb.Push(result);
294}
295
296void IHidServer::ActivateKeyboard(HLERequestContext& ctx) {
297 IPC::RequestParser rp{ctx};
298 const auto applet_resource_user_id{rp.Pop<u64>()};
299
300 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
301
302 Result result = ResultSuccess;
303 auto& keyboard =
304 GetResourceManager()->GetController<Controller_Keyboard>(HidController::Keyboard);
305
306 if (!firmware_settings->IsDeviceManaged()) {
307 result = keyboard.Activate();
308 }
309
310 if (result.IsSuccess()) {
311 result = keyboard.Activate(applet_resource_user_id);
312 }
313
314 IPC::ResponseBuilder rb{ctx, 2};
315 rb.Push(result);
316}
317
318void IHidServer::SendKeyboardLockKeyEvent(HLERequestContext& ctx) {
319 IPC::RequestParser rp{ctx};
320 const auto flags{rp.Pop<u32>()};
321
322 LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
323
324 IPC::ResponseBuilder rb{ctx, 2};
325 rb.Push(ResultSuccess);
326}
327
328void IHidServer::AcquireXpadIdEventHandle(HLERequestContext& ctx) {
329 IPC::RequestParser rp{ctx};
330 const auto applet_resource_user_id{rp.Pop<u64>()};
331
332 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
333
334 // This function has been stubbed since 10.0.0+
335
336 IPC::ResponseBuilder rb{ctx, 2, 1};
337 rb.Push(ResultSuccess);
338 // Handle returned is null here
339}
340
341void IHidServer::ReleaseXpadIdEventHandle(HLERequestContext& ctx) {
342 IPC::RequestParser rp{ctx};
343 const auto applet_resource_user_id{rp.Pop<u64>()};
344
345 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
346
347 // This function has been stubbed since 10.0.0+
348
349 IPC::ResponseBuilder rb{ctx, 2};
350 rb.Push(ResultSuccess);
351}
352
353void IHidServer::ActivateXpad(HLERequestContext& ctx) {
354 IPC::RequestParser rp{ctx};
355 struct Parameters {
356 u32 basic_xpad_id;
357 INSERT_PADDING_WORDS_NOINIT(1);
358 u64 applet_resource_user_id;
359 };
360 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
361
362 const auto parameters{rp.PopRaw<Parameters>()};
363
364 LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
365 parameters.basic_xpad_id, parameters.applet_resource_user_id);
366
367 // This function has been stubbed since 10.0.0+
368
369 IPC::ResponseBuilder rb{ctx, 2};
370 rb.Push(ResultSuccess);
371}
372
373void IHidServer::GetXpadIds(HLERequestContext& ctx) {
374 LOG_DEBUG(Service_HID, "called");
375
376 // This function has been hardcoded since 10.0.0+
377 const std::array<u32, 4> basic_xpad_id{0, 1, 2, 3};
378 ctx.WriteBuffer(basic_xpad_id);
379
380 IPC::ResponseBuilder rb{ctx, 4};
381 rb.Push(ResultSuccess);
382 rb.Push<s64>(basic_xpad_id.size());
383}
384
385void IHidServer::ActivateJoyXpad(HLERequestContext& ctx) {
386 IPC::RequestParser rp{ctx};
387 const auto joy_xpad_id{rp.Pop<u32>()};
388
389 LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
390
391 // This function has been stubbed since 10.0.0+
392
393 IPC::ResponseBuilder rb{ctx, 2};
394 rb.Push(ResultSuccess);
395}
396
397void IHidServer::GetJoyXpadLifoHandle(HLERequestContext& ctx) {
398 IPC::RequestParser rp{ctx};
399 const auto joy_xpad_id{rp.Pop<u32>()};
400
401 LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
402
403 // This function has been stubbed since 10.0.0+
404
405 IPC::ResponseBuilder rb{ctx, 2, 1};
406 rb.Push(ResultSuccess);
407 // Handle returned is null here
408}
409
410void IHidServer::GetJoyXpadIds(HLERequestContext& ctx) {
411 LOG_DEBUG(Service_HID, "called");
412
413 // This function has been hardcoded since 10.0.0+
414 const s64 basic_xpad_id_count{};
415
416 IPC::ResponseBuilder rb{ctx, 4};
417 rb.Push(ResultSuccess);
418 rb.Push(basic_xpad_id_count);
419}
420
421void IHidServer::ActivateSixAxisSensor(HLERequestContext& ctx) {
422 IPC::RequestParser rp{ctx};
423 const auto joy_xpad_id{rp.Pop<u32>()};
424
425 LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
426
427 // This function has been stubbed since 10.0.0+
428
429 IPC::ResponseBuilder rb{ctx, 2};
430 rb.Push(ResultSuccess);
431}
432
433void IHidServer::DeactivateSixAxisSensor(HLERequestContext& ctx) {
434 IPC::RequestParser rp{ctx};
435 const auto joy_xpad_id{rp.Pop<u32>()};
436
437 LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
438
439 // This function has been stubbed since 10.0.0+
440
441 IPC::ResponseBuilder rb{ctx, 2, 1};
442 rb.Push(ResultSuccess);
443}
444
445void IHidServer::GetSixAxisSensorLifoHandle(HLERequestContext& ctx) {
446 IPC::RequestParser rp{ctx};
447 const auto joy_xpad_id{rp.Pop<u32>()};
448
449 LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
450
451 // This function has been stubbed since 10.0.0+
452
453 IPC::ResponseBuilder rb{ctx, 2};
454 rb.Push(ResultSuccess);
455}
456
457void IHidServer::ActivateJoySixAxisSensor(HLERequestContext& ctx) {
458 IPC::RequestParser rp{ctx};
459 const auto joy_xpad_id{rp.Pop<u32>()};
460
461 LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
462
463 // This function has been stubbed since 10.0.0+
464
465 IPC::ResponseBuilder rb{ctx, 2};
466 rb.Push(ResultSuccess);
467}
468
469void IHidServer::DeactivateJoySixAxisSensor(HLERequestContext& ctx) {
470 IPC::RequestParser rp{ctx};
471 const auto joy_xpad_id{rp.Pop<u32>()};
472
473 LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
474
475 // This function has been stubbed since 10.0.0+
476
477 IPC::ResponseBuilder rb{ctx, 2};
478 rb.Push(ResultSuccess);
479}
480
481void IHidServer::GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx) {
482 IPC::RequestParser rp{ctx};
483 const auto joy_xpad_id{rp.Pop<u32>()};
484
485 LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
486
487 // This function has been stubbed since 10.0.0+
488
489 IPC::ResponseBuilder rb{ctx, 2, 1};
490 rb.Push(ResultSuccess);
491 // Handle returned is null here
492}
493
494void IHidServer::StartSixAxisSensor(HLERequestContext& ctx) {
495 IPC::RequestParser rp{ctx};
496 struct Parameters {
497 Core::HID::SixAxisSensorHandle sixaxis_handle;
498 INSERT_PADDING_WORDS_NOINIT(1);
499 u64 applet_resource_user_id;
500 };
501 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
502
503 const auto parameters{rp.PopRaw<Parameters>()};
504
505 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
506 const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, true);
507
508 LOG_DEBUG(Service_HID,
509 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
510 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
511 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
512
513 IPC::ResponseBuilder rb{ctx, 2};
514 rb.Push(result);
515}
516
517void IHidServer::StopSixAxisSensor(HLERequestContext& ctx) {
518 IPC::RequestParser rp{ctx};
519 struct Parameters {
520 Core::HID::SixAxisSensorHandle sixaxis_handle;
521 INSERT_PADDING_WORDS_NOINIT(1);
522 u64 applet_resource_user_id;
523 };
524 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
525
526 const auto parameters{rp.PopRaw<Parameters>()};
527
528 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
529 const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, false);
530
531 LOG_DEBUG(Service_HID,
532 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
533 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
534 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
535
536 IPC::ResponseBuilder rb{ctx, 2};
537 rb.Push(result);
538}
539
540void IHidServer::IsSixAxisSensorFusionEnabled(HLERequestContext& ctx) {
541 IPC::RequestParser rp{ctx};
542 struct Parameters {
543 Core::HID::SixAxisSensorHandle sixaxis_handle;
544 INSERT_PADDING_WORDS_NOINIT(1);
545 u64 applet_resource_user_id;
546 };
547 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
548
549 const auto parameters{rp.PopRaw<Parameters>()};
550
551 bool is_enabled{};
552 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
553 const auto result =
554 controller.IsSixAxisSensorFusionEnabled(parameters.sixaxis_handle, is_enabled);
555
556 LOG_DEBUG(Service_HID,
557 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
558 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
559 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
560
561 IPC::ResponseBuilder rb{ctx, 3};
562 rb.Push(result);
563 rb.Push(is_enabled);
564}
565
566void IHidServer::EnableSixAxisSensorFusion(HLERequestContext& ctx) {
567 IPC::RequestParser rp{ctx};
568 struct Parameters {
569 bool enable_sixaxis_sensor_fusion;
570 INSERT_PADDING_BYTES_NOINIT(3);
571 Core::HID::SixAxisSensorHandle sixaxis_handle;
572 u64 applet_resource_user_id;
573 };
574 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
575
576 const auto parameters{rp.PopRaw<Parameters>()};
577
578 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
579 const auto result = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle,
580 parameters.enable_sixaxis_sensor_fusion);
581
582 LOG_DEBUG(Service_HID,
583 "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
584 "device_index={}, applet_resource_user_id={}",
585 parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
586 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
587 parameters.applet_resource_user_id);
588
589 IPC::ResponseBuilder rb{ctx, 2};
590 rb.Push(result);
591}
592
593void IHidServer::SetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
594 IPC::RequestParser rp{ctx};
595 struct Parameters {
596 Core::HID::SixAxisSensorHandle sixaxis_handle;
597 Core::HID::SixAxisSensorFusionParameters sixaxis_fusion;
598 INSERT_PADDING_WORDS_NOINIT(1);
599 u64 applet_resource_user_id;
600 };
601 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
602
603 const auto parameters{rp.PopRaw<Parameters>()};
604
605 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
606 const auto result =
607 controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion);
608
609 LOG_DEBUG(Service_HID,
610 "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, "
611 "parameter2={}, applet_resource_user_id={}",
612 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
613 parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1,
614 parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id);
615
616 IPC::ResponseBuilder rb{ctx, 2};
617 rb.Push(result);
618}
619
620void IHidServer::GetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
621 IPC::RequestParser rp{ctx};
622 struct Parameters {
623 Core::HID::SixAxisSensorHandle sixaxis_handle;
624 INSERT_PADDING_WORDS_NOINIT(1);
625 u64 applet_resource_user_id;
626 };
627 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
628
629 const auto parameters{rp.PopRaw<Parameters>()};
630
631 Core::HID::SixAxisSensorFusionParameters fusion_parameters{};
632 const auto& controller =
633 GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
634 const auto result =
635 controller.GetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
636
637 LOG_DEBUG(Service_HID,
638 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
639 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
640 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
641
642 IPC::ResponseBuilder rb{ctx, 4};
643 rb.Push(result);
644 rb.PushRaw(fusion_parameters);
645}
646
647void IHidServer::ResetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
648 IPC::RequestParser rp{ctx};
649 struct Parameters {
650 Core::HID::SixAxisSensorHandle sixaxis_handle;
651 INSERT_PADDING_WORDS_NOINIT(1);
652 u64 applet_resource_user_id;
653 };
654 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
655
656 const auto parameters{rp.PopRaw<Parameters>()};
657
658 // Since these parameters are unknown just use what HW outputs
659 const Core::HID::SixAxisSensorFusionParameters fusion_parameters{
660 .parameter1 = 0.03f,
661 .parameter2 = 0.4f,
662 };
663 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
664 const auto result1 =
665 controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
666 const auto result2 = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle, true);
667
668 LOG_DEBUG(Service_HID,
669 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
670 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
671 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
672
673 IPC::ResponseBuilder rb{ctx, 2};
674 if (result1.IsError()) {
675 rb.Push(result1);
676 return;
677 }
678 rb.Push(result2);
679}
680
681void IHidServer::SetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
682 IPC::RequestParser rp{ctx};
683 const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()};
684 const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()};
685 const auto applet_resource_user_id{rp.Pop<u64>()};
686
687 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
688 const auto result = controller.SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode);
689
690 LOG_DEBUG(Service_HID,
691 "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
692 "applet_resource_user_id={}",
693 sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index,
694 drift_mode, applet_resource_user_id);
695
696 IPC::ResponseBuilder rb{ctx, 2};
697 rb.Push(result);
698}
699
700void IHidServer::GetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
701 IPC::RequestParser rp{ctx};
702 struct Parameters {
703 Core::HID::SixAxisSensorHandle sixaxis_handle;
704 INSERT_PADDING_WORDS_NOINIT(1);
705 u64 applet_resource_user_id;
706 };
707 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
708
709 const auto parameters{rp.PopRaw<Parameters>()};
710
711 auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
712 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
713 const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
714
715 LOG_DEBUG(Service_HID,
716 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
717 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
718 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
719
720 IPC::ResponseBuilder rb{ctx, 3};
721 rb.Push(result);
722 rb.PushEnum(drift_mode);
723}
724
725void IHidServer::ResetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
726 IPC::RequestParser rp{ctx};
727 struct Parameters {
728 Core::HID::SixAxisSensorHandle sixaxis_handle;
729 INSERT_PADDING_WORDS_NOINIT(1);
730 u64 applet_resource_user_id;
731 };
732 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
733
734 const auto parameters{rp.PopRaw<Parameters>()};
735
736 const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
737 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
738 const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
739
740 LOG_DEBUG(Service_HID,
741 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
742 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
743 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
744
745 IPC::ResponseBuilder rb{ctx, 2};
746 rb.Push(result);
747}
748
749void IHidServer::IsSixAxisSensorAtRest(HLERequestContext& ctx) {
750 IPC::RequestParser rp{ctx};
751 struct Parameters {
752 Core::HID::SixAxisSensorHandle sixaxis_handle;
753 INSERT_PADDING_WORDS_NOINIT(1);
754 u64 applet_resource_user_id;
755 };
756 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
757
758 const auto parameters{rp.PopRaw<Parameters>()};
759
760 bool is_at_rest{};
761 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
762 controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
763
764 LOG_DEBUG(Service_HID,
765 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
766 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
767 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
768
769 IPC::ResponseBuilder rb{ctx, 3};
770 rb.Push(ResultSuccess);
771 rb.Push(is_at_rest);
772}
773
774void IHidServer::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx) {
775 IPC::RequestParser rp{ctx};
776 struct Parameters {
777 Core::HID::SixAxisSensorHandle sixaxis_handle;
778 INSERT_PADDING_WORDS_NOINIT(1);
779 u64 applet_resource_user_id;
780 };
781 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
782
783 const auto parameters{rp.PopRaw<Parameters>()};
784
785 bool is_firmware_available{};
786 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
787 controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle,
788 is_firmware_available);
789
790 LOG_WARNING(
791 Service_HID,
792 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
793 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
794 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
795
796 IPC::ResponseBuilder rb{ctx, 3};
797 rb.Push(ResultSuccess);
798 rb.Push(is_firmware_available);
799}
800
801void IHidServer::EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx) {
802 IPC::RequestParser rp{ctx};
803 struct Parameters {
804 bool enabled;
805 Core::HID::SixAxisSensorHandle sixaxis_handle;
806 u64 applet_resource_user_id;
807 };
808 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
809
810 const auto parameters{rp.PopRaw<Parameters>()};
811
812 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
813 const auto result = controller.EnableSixAxisSensorUnalteredPassthrough(
814 parameters.sixaxis_handle, parameters.enabled);
815
816 LOG_DEBUG(Service_HID,
817 "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, "
818 "applet_resource_user_id={}",
819 parameters.enabled, parameters.sixaxis_handle.npad_type,
820 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
821 parameters.applet_resource_user_id);
822
823 IPC::ResponseBuilder rb{ctx, 2};
824 rb.Push(result);
825}
826
827void IHidServer::IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx) {
828 IPC::RequestParser rp{ctx};
829 struct Parameters {
830 Core::HID::SixAxisSensorHandle sixaxis_handle;
831 INSERT_PADDING_WORDS_NOINIT(1);
832 u64 applet_resource_user_id;
833 };
834 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
835
836 const auto parameters{rp.PopRaw<Parameters>()};
837
838 bool is_unaltered_sisxaxis_enabled{};
839 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
840 const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled(
841 parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled);
842
843 LOG_DEBUG(
844 Service_HID,
845 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
846 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
847 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
848
849 IPC::ResponseBuilder rb{ctx, 3};
850 rb.Push(result);
851 rb.Push(is_unaltered_sisxaxis_enabled);
852}
853
854void IHidServer::LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx) {
855 IPC::RequestParser rp{ctx};
856 struct Parameters {
857 Core::HID::SixAxisSensorHandle sixaxis_handle;
858 INSERT_PADDING_WORDS_NOINIT(1);
859 u64 applet_resource_user_id;
860 };
861 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
862
863 const auto parameters{rp.PopRaw<Parameters>()};
864
865 Core::HID::SixAxisSensorCalibrationParameter calibration{};
866 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
867 const auto result =
868 controller.LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration);
869
870 LOG_WARNING(
871 Service_HID,
872 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
873 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
874 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
875
876 if (result.IsSuccess()) {
877 ctx.WriteBuffer(calibration);
878 }
879
880 IPC::ResponseBuilder rb{ctx, 2};
881 rb.Push(result);
882}
883
884void IHidServer::GetSixAxisSensorIcInformation(HLERequestContext& ctx) {
885 IPC::RequestParser rp{ctx};
886 struct Parameters {
887 Core::HID::SixAxisSensorHandle sixaxis_handle;
888 INSERT_PADDING_WORDS_NOINIT(1);
889 u64 applet_resource_user_id;
890 };
891 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
892
893 const auto parameters{rp.PopRaw<Parameters>()};
894
895 Core::HID::SixAxisSensorIcInformation ic_information{};
896 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
897 const auto result =
898 controller.GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information);
899
900 LOG_WARNING(
901 Service_HID,
902 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
903 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
904 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
905
906 if (result.IsSuccess()) {
907 ctx.WriteBuffer(ic_information);
908 }
909
910 IPC::ResponseBuilder rb{ctx, 2};
911 rb.Push(result);
912}
913
914void IHidServer::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx) {
915 IPC::RequestParser rp{ctx};
916 struct Parameters {
917 Core::HID::SixAxisSensorHandle sixaxis_handle;
918 INSERT_PADDING_WORDS_NOINIT(1);
919 u64 applet_resource_user_id;
920 };
921 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
922
923 const auto parameters{rp.PopRaw<Parameters>()};
924
925 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
926 const auto result =
927 controller.ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle);
928
929 LOG_WARNING(
930 Service_HID,
931 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
932 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
933 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
934
935 IPC::ResponseBuilder rb{ctx, 2};
936 rb.Push(result);
937}
938
939void IHidServer::ActivateGesture(HLERequestContext& ctx) {
940 IPC::RequestParser rp{ctx};
941 struct Parameters {
942 u32 basic_gesture_id;
943 INSERT_PADDING_WORDS_NOINIT(1);
944 u64 applet_resource_user_id;
945 };
946 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
947
948 const auto parameters{rp.PopRaw<Parameters>()};
949
950 LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
951 parameters.basic_gesture_id, parameters.applet_resource_user_id);
952
953 Result result = ResultSuccess;
954 auto& gesture = GetResourceManager()->GetController<Controller_Gesture>(HidController::Gesture);
955
956 if (!firmware_settings->IsDeviceManaged()) {
957 result = gesture.Activate();
958 }
959
960 if (result.IsSuccess()) {
961 // TODO: Use gesture id here
962 result = gesture.Activate(parameters.applet_resource_user_id);
963 }
964
965 IPC::ResponseBuilder rb{ctx, 2};
966 rb.Push(result);
967}
968
969void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) {
970 IPC::RequestParser rp{ctx};
971 struct Parameters {
972 Core::HID::NpadStyleSet supported_styleset;
973 INSERT_PADDING_WORDS_NOINIT(1);
974 u64 applet_resource_user_id;
975 };
976 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
977
978 const auto parameters{rp.PopRaw<Parameters>()};
979
980 GetResourceManager()
981 ->GetController<Controller_NPad>(HidController::NPad)
982 .SetSupportedStyleSet({parameters.supported_styleset});
983
984 LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}",
985 parameters.supported_styleset, parameters.applet_resource_user_id);
986
987 IPC::ResponseBuilder rb{ctx, 2};
988 rb.Push(ResultSuccess);
989}
990
991void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) {
992 IPC::RequestParser rp{ctx};
993 const auto applet_resource_user_id{rp.Pop<u64>()};
994
995 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
996
997 IPC::ResponseBuilder rb{ctx, 3};
998 rb.Push(ResultSuccess);
999 rb.PushEnum(GetResourceManager()
1000 ->GetController<Controller_NPad>(HidController::NPad)
1001 .GetSupportedStyleSet()
1002 .raw);
1003}
1004
1005void IHidServer::SetSupportedNpadIdType(HLERequestContext& ctx) {
1006 IPC::RequestParser rp{ctx};
1007 const auto applet_resource_user_id{rp.Pop<u64>()};
1008
1009 const auto result = GetResourceManager()
1010 ->GetController<Controller_NPad>(HidController::NPad)
1011 .SetSupportedNpadIdTypes(ctx.ReadBuffer());
1012
1013 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1014
1015 IPC::ResponseBuilder rb{ctx, 2};
1016 rb.Push(result);
1017}
1018
1019void IHidServer::ActivateNpad(HLERequestContext& ctx) {
1020 IPC::RequestParser rp{ctx};
1021 const auto applet_resource_user_id{rp.Pop<u64>()};
1022
1023 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1024
1025 auto& npad = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1026
1027 // TODO: npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0);
1028 const Result result = npad.Activate(applet_resource_user_id);
1029
1030 IPC::ResponseBuilder rb{ctx, 2};
1031 rb.Push(result);
1032}
1033
1034void IHidServer::DeactivateNpad(HLERequestContext& ctx) {
1035 IPC::RequestParser rp{ctx};
1036 const auto applet_resource_user_id{rp.Pop<u64>()};
1037
1038 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1039
1040 // This function does nothing since 10.0.0+
1041
1042 IPC::ResponseBuilder rb{ctx, 2};
1043 rb.Push(ResultSuccess);
1044}
1045
1046void IHidServer::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) {
1047 IPC::RequestParser rp{ctx};
1048 struct Parameters {
1049 Core::HID::NpadIdType npad_id;
1050 INSERT_PADDING_WORDS_NOINIT(1);
1051 u64 applet_resource_user_id;
1052 u64 unknown;
1053 };
1054 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1055
1056 const auto parameters{rp.PopRaw<Parameters>()};
1057
1058 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
1059 parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
1060
1061 // Games expect this event to be signaled after calling this function
1062 GetResourceManager()
1063 ->GetController<Controller_NPad>(HidController::NPad)
1064 .SignalStyleSetChangedEvent(parameters.npad_id);
1065
1066 IPC::ResponseBuilder rb{ctx, 2, 1};
1067 rb.Push(ResultSuccess);
1068 rb.PushCopyObjects(GetResourceManager()
1069 ->GetController<Controller_NPad>(HidController::NPad)
1070 .GetStyleSetChangedEvent(parameters.npad_id));
1071}
1072
1073void IHidServer::DisconnectNpad(HLERequestContext& ctx) {
1074 IPC::RequestParser rp{ctx};
1075 struct Parameters {
1076 Core::HID::NpadIdType npad_id;
1077 INSERT_PADDING_WORDS_NOINIT(1);
1078 u64 applet_resource_user_id;
1079 };
1080 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1081
1082 const auto parameters{rp.PopRaw<Parameters>()};
1083
1084 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1085 controller.DisconnectNpad(parameters.npad_id);
1086
1087 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1088 parameters.applet_resource_user_id);
1089
1090 IPC::ResponseBuilder rb{ctx, 2};
1091 rb.Push(ResultSuccess);
1092}
1093
1094void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
1095 IPC::RequestParser rp{ctx};
1096 const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
1097
1098 Core::HID::LedPattern pattern{0, 0, 0, 0};
1099 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1100 const auto result = controller.GetLedPattern(npad_id, pattern);
1101
1102 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
1103
1104 IPC::ResponseBuilder rb{ctx, 4};
1105 rb.Push(result);
1106 rb.Push(pattern.raw);
1107}
1108
1109void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
1110 IPC::RequestParser rp{ctx};
1111 struct Parameters {
1112 Controller_NPad::NpadRevision revision;
1113 INSERT_PADDING_WORDS_NOINIT(1);
1114 u64 applet_resource_user_id;
1115 };
1116 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1117
1118 const auto parameters{rp.PopRaw<Parameters>()};
1119
1120 LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision,
1121 parameters.applet_resource_user_id);
1122
1123 auto& npad = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1124
1125 // TODO: npad->SetRevision(applet_resource_user_id, revision);
1126 const auto result = npad.Activate(parameters.applet_resource_user_id);
1127
1128 IPC::ResponseBuilder rb{ctx, 2};
1129 rb.Push(result);
1130}
1131
1132void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) {
1133 IPC::RequestParser rp{ctx};
1134 const auto applet_resource_user_id{rp.Pop<u64>()};
1135 const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()};
1136
1137 GetResourceManager()
1138 ->GetController<Controller_NPad>(HidController::NPad)
1139 .SetHoldType(hold_type);
1140
1141 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
1142 applet_resource_user_id, hold_type);
1143
1144 IPC::ResponseBuilder rb{ctx, 2};
1145 rb.Push(ResultSuccess);
1146}
1147
1148void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) {
1149 IPC::RequestParser rp{ctx};
1150 const auto applet_resource_user_id{rp.Pop<u64>()};
1151
1152 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1153
1154 IPC::ResponseBuilder rb{ctx, 4};
1155 rb.Push(ResultSuccess);
1156 rb.PushEnum(
1157 GetResourceManager()->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
1158}
1159
1160void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) {
1161 IPC::RequestParser rp{ctx};
1162 struct Parameters {
1163 Core::HID::NpadIdType npad_id;
1164 INSERT_PADDING_WORDS_NOINIT(1);
1165 u64 applet_resource_user_id;
1166 };
1167 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1168
1169 const auto parameters{rp.PopRaw<Parameters>()};
1170
1171 Core::HID::NpadIdType new_npad_id{};
1172 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1173 controller.SetNpadMode(new_npad_id, parameters.npad_id,
1174 Controller_NPad::NpadJoyDeviceType::Left,
1175 Controller_NPad::NpadJoyAssignmentMode::Single);
1176
1177 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1178 parameters.applet_resource_user_id);
1179
1180 IPC::ResponseBuilder rb{ctx, 2};
1181 rb.Push(ResultSuccess);
1182}
1183
1184void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
1185 IPC::RequestParser rp{ctx};
1186 struct Parameters {
1187 Core::HID::NpadIdType npad_id;
1188 INSERT_PADDING_WORDS_NOINIT(1);
1189 u64 applet_resource_user_id;
1190 Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
1191 };
1192 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1193
1194 const auto parameters{rp.PopRaw<Parameters>()};
1195
1196 Core::HID::NpadIdType new_npad_id{};
1197 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1198 controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
1199 Controller_NPad::NpadJoyAssignmentMode::Single);
1200
1201 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1202 parameters.npad_id, parameters.applet_resource_user_id,
1203 parameters.npad_joy_device_type);
1204
1205 IPC::ResponseBuilder rb{ctx, 2};
1206 rb.Push(ResultSuccess);
1207}
1208
1209void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
1210 IPC::RequestParser rp{ctx};
1211 struct Parameters {
1212 Core::HID::NpadIdType npad_id;
1213 INSERT_PADDING_WORDS_NOINIT(1);
1214 u64 applet_resource_user_id;
1215 };
1216 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1217
1218 const auto parameters{rp.PopRaw<Parameters>()};
1219
1220 Core::HID::NpadIdType new_npad_id{};
1221 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1222 controller.SetNpadMode(new_npad_id, parameters.npad_id, {},
1223 Controller_NPad::NpadJoyAssignmentMode::Dual);
1224
1225 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1226 parameters.applet_resource_user_id);
1227
1228 IPC::ResponseBuilder rb{ctx, 2};
1229 rb.Push(ResultSuccess);
1230}
1231
1232void IHidServer::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) {
1233 IPC::RequestParser rp{ctx};
1234 const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
1235 const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
1236 const auto applet_resource_user_id{rp.Pop<u64>()};
1237
1238 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1239 const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
1240
1241 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
1242 npad_id_1, npad_id_2, applet_resource_user_id);
1243
1244 IPC::ResponseBuilder rb{ctx, 2};
1245 rb.Push(result);
1246}
1247
1248void IHidServer::StartLrAssignmentMode(HLERequestContext& ctx) {
1249 IPC::RequestParser rp{ctx};
1250 const auto applet_resource_user_id{rp.Pop<u64>()};
1251
1252 GetResourceManager()
1253 ->GetController<Controller_NPad>(HidController::NPad)
1254 .StartLRAssignmentMode();
1255
1256 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1257
1258 IPC::ResponseBuilder rb{ctx, 2};
1259 rb.Push(ResultSuccess);
1260}
1261
1262void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) {
1263 IPC::RequestParser rp{ctx};
1264 const auto applet_resource_user_id{rp.Pop<u64>()};
1265
1266 GetResourceManager()
1267 ->GetController<Controller_NPad>(HidController::NPad)
1268 .StopLRAssignmentMode();
1269
1270 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1271
1272 IPC::ResponseBuilder rb{ctx, 2};
1273 rb.Push(ResultSuccess);
1274}
1275
1276void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
1277 IPC::RequestParser rp{ctx};
1278 const auto applet_resource_user_id{rp.Pop<u64>()};
1279 const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};
1280
1281 GetResourceManager()
1282 ->GetController<Controller_NPad>(HidController::NPad)
1283 .SetNpadHandheldActivationMode(activation_mode);
1284
1285 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}",
1286 applet_resource_user_id, activation_mode);
1287
1288 IPC::ResponseBuilder rb{ctx, 2};
1289 rb.Push(ResultSuccess);
1290}
1291
1292void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) {
1293 IPC::RequestParser rp{ctx};
1294 const auto applet_resource_user_id{rp.Pop<u64>()};
1295
1296 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1297
1298 IPC::ResponseBuilder rb{ctx, 4};
1299 rb.Push(ResultSuccess);
1300 rb.PushEnum(GetResourceManager()
1301 ->GetController<Controller_NPad>(HidController::NPad)
1302 .GetNpadHandheldActivationMode());
1303}
1304
1305void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) {
1306 IPC::RequestParser rp{ctx};
1307 const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
1308 const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
1309 const auto applet_resource_user_id{rp.Pop<u64>()};
1310
1311 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1312 const auto result = controller.SwapNpadAssignment(npad_id_1, npad_id_2);
1313
1314 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
1315 npad_id_1, npad_id_2, applet_resource_user_id);
1316
1317 IPC::ResponseBuilder rb{ctx, 2};
1318 rb.Push(result);
1319}
1320
1321void IHidServer::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx) {
1322 IPC::RequestParser rp{ctx};
1323 struct Parameters {
1324 Core::HID::NpadIdType npad_id;
1325 INSERT_PADDING_WORDS_NOINIT(1);
1326 u64 applet_resource_user_id;
1327 };
1328 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1329
1330 const auto parameters{rp.PopRaw<Parameters>()};
1331
1332 bool is_enabled = false;
1333 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1334 const auto result =
1335 controller.IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled);
1336
1337 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
1338 parameters.npad_id, parameters.applet_resource_user_id);
1339
1340 IPC::ResponseBuilder rb{ctx, 3};
1341 rb.Push(result);
1342 rb.Push(is_enabled);
1343}
1344
1345void IHidServer::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) {
1346 IPC::RequestParser rp{ctx};
1347 struct Parameters {
1348 bool is_enabled;
1349 INSERT_PADDING_BYTES_NOINIT(3);
1350 Core::HID::NpadIdType npad_id;
1351 u64 applet_resource_user_id;
1352 };
1353 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1354
1355 const auto parameters{rp.PopRaw<Parameters>()};
1356
1357 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1358 const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled(
1359 parameters.is_enabled, parameters.npad_id);
1360
1361 LOG_DEBUG(Service_HID,
1362 "(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}",
1363 parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id);
1364
1365 IPC::ResponseBuilder rb{ctx, 2};
1366 rb.Push(result);
1367}
1368
1369void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx) {
1370 IPC::RequestParser rp{ctx};
1371 struct Parameters {
1372 Core::HID::NpadIdType npad_id;
1373 INSERT_PADDING_WORDS_NOINIT(1);
1374 u64 applet_resource_user_id;
1375 Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
1376 };
1377 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1378
1379 const auto parameters{rp.PopRaw<Parameters>()};
1380
1381 Core::HID::NpadIdType new_npad_id{};
1382 auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1383 const auto is_reassigned =
1384 controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
1385 Controller_NPad::NpadJoyAssignmentMode::Single);
1386
1387 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1388 parameters.npad_id, parameters.applet_resource_user_id,
1389 parameters.npad_joy_device_type);
1390
1391 IPC::ResponseBuilder rb{ctx, 4};
1392 rb.Push(ResultSuccess);
1393 rb.Push(is_reassigned);
1394 rb.PushEnum(new_npad_id);
1395}
1396
1397void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
1398 IPC::RequestParser rp{ctx};
1399 struct Parameters {
1400 bool analog_stick_use_center_clamp;
1401 INSERT_PADDING_BYTES_NOINIT(7);
1402 u64 applet_resource_user_id;
1403 };
1404 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1405
1406 const auto parameters{rp.PopRaw<Parameters>()};
1407
1408 GetResourceManager()
1409 ->GetController<Controller_NPad>(HidController::NPad)
1410 .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
1411
1412 LOG_WARNING(Service_HID,
1413 "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
1414 parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id);
1415
1416 IPC::ResponseBuilder rb{ctx, 2};
1417 rb.Push(ResultSuccess);
1418}
1419
1420void IHidServer::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
1421 IPC::RequestParser rp{ctx};
1422 struct Parameters {
1423 Core::HID::NpadStyleSet npad_styleset;
1424 INSERT_PADDING_WORDS_NOINIT(1);
1425 u64 applet_resource_user_id;
1426 Core::HID::NpadButton button;
1427 };
1428 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1429
1430 const auto parameters{rp.PopRaw<Parameters>()};
1431
1432 LOG_WARNING(Service_HID,
1433 "(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}",
1434 parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
1435
1436 IPC::ResponseBuilder rb{ctx, 2};
1437 rb.Push(ResultSuccess);
1438}
1439
1440void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
1441 IPC::RequestParser rp{ctx};
1442 const auto applet_resource_user_id{rp.Pop<u64>()};
1443
1444 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1445 applet_resource_user_id);
1446
1447 IPC::ResponseBuilder rb{ctx, 2};
1448 rb.Push(ResultSuccess);
1449}
1450
1451void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
1452 IPC::RequestParser rp{ctx};
1453 const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
1454 const auto& controller =
1455 GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
1456
1457 Core::HID::VibrationDeviceInfo vibration_device_info;
1458 bool check_device_index = false;
1459
1460 switch (vibration_device_handle.npad_type) {
1461 case Core::HID::NpadStyleIndex::ProController:
1462 case Core::HID::NpadStyleIndex::Handheld:
1463 case Core::HID::NpadStyleIndex::JoyconDual:
1464 case Core::HID::NpadStyleIndex::JoyconLeft:
1465 case Core::HID::NpadStyleIndex::JoyconRight:
1466 vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
1467 check_device_index = true;
1468 break;
1469 case Core::HID::NpadStyleIndex::GameCube:
1470 vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
1471 break;
1472 case Core::HID::NpadStyleIndex::N64:
1473 vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
1474 break;
1475 default:
1476 vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
1477 break;
1478 }
1479
1480 vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
1481 if (check_device_index) {
1482 switch (vibration_device_handle.device_index) {
1483 case Core::HID::DeviceIndex::Left:
1484 vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
1485 break;
1486 case Core::HID::DeviceIndex::Right:
1487 vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
1488 break;
1489 case Core::HID::DeviceIndex::None:
1490 default:
1491 ASSERT_MSG(false, "DeviceIndex should never be None!");
1492 break;
1493 }
1494 }
1495
1496 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
1497 vibration_device_info.type, vibration_device_info.position);
1498
1499 const auto result = controller.IsDeviceHandleValid(vibration_device_handle);
1500 if (result.IsError()) {
1501 IPC::ResponseBuilder rb{ctx, 2};
1502 rb.Push(result);
1503 return;
1504 }
1505
1506 IPC::ResponseBuilder rb{ctx, 4};
1507 rb.Push(ResultSuccess);
1508 rb.PushRaw(vibration_device_info);
1509}
1510
1511void IHidServer::SendVibrationValue(HLERequestContext& ctx) {
1512 IPC::RequestParser rp{ctx};
1513 struct Parameters {
1514 Core::HID::VibrationDeviceHandle vibration_device_handle;
1515 Core::HID::VibrationValue vibration_value;
1516 INSERT_PADDING_WORDS_NOINIT(1);
1517 u64 applet_resource_user_id;
1518 };
1519 static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
1520
1521 const auto parameters{rp.PopRaw<Parameters>()};
1522
1523 GetResourceManager()
1524 ->GetController<Controller_NPad>(HidController::NPad)
1525 .VibrateController(parameters.vibration_device_handle, parameters.vibration_value);
1526
1527 LOG_DEBUG(Service_HID,
1528 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1529 parameters.vibration_device_handle.npad_type,
1530 parameters.vibration_device_handle.npad_id,
1531 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1532
1533 IPC::ResponseBuilder rb{ctx, 2};
1534 rb.Push(ResultSuccess);
1535}
1536
1537void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) {
1538 IPC::RequestParser rp{ctx};
1539 struct Parameters {
1540 Core::HID::VibrationDeviceHandle vibration_device_handle;
1541 INSERT_PADDING_WORDS_NOINIT(1);
1542 u64 applet_resource_user_id;
1543 };
1544 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1545
1546 const auto parameters{rp.PopRaw<Parameters>()};
1547
1548 LOG_DEBUG(Service_HID,
1549 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1550 parameters.vibration_device_handle.npad_type,
1551 parameters.vibration_device_handle.npad_id,
1552 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1553
1554 IPC::ResponseBuilder rb{ctx, 6};
1555 rb.Push(ResultSuccess);
1556 rb.PushRaw(GetResourceManager()
1557 ->GetController<Controller_NPad>(HidController::NPad)
1558 .GetLastVibration(parameters.vibration_device_handle));
1559}
1560
1561void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) {
1562 LOG_DEBUG(Service_HID, "called");
1563
1564 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1565 rb.Push(ResultSuccess);
1566 rb.PushIpcInterface<IActiveVibrationDeviceList>(system, resource_manager);
1567}
1568
1569void IHidServer::PermitVibration(HLERequestContext& ctx) {
1570 IPC::RequestParser rp{ctx};
1571 const auto can_vibrate{rp.Pop<bool>()};
1572
1573 // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value
1574 // by converting it to a bool
1575 Settings::values.vibration_enabled.SetValue(can_vibrate);
1576
1577 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
1578
1579 IPC::ResponseBuilder rb{ctx, 2};
1580 rb.Push(ResultSuccess);
1581}
1582
1583void IHidServer::IsVibrationPermitted(HLERequestContext& ctx) {
1584 LOG_DEBUG(Service_HID, "called");
1585
1586 // nnSDK checks if a float is greater than zero. We return the bool we stored earlier
1587 const auto is_enabled = Settings::values.vibration_enabled.GetValue();
1588
1589 IPC::ResponseBuilder rb{ctx, 3};
1590 rb.Push(ResultSuccess);
1591 rb.Push(is_enabled);
1592}
1593
1594void IHidServer::SendVibrationValues(HLERequestContext& ctx) {
1595 IPC::RequestParser rp{ctx};
1596 const auto applet_resource_user_id{rp.Pop<u64>()};
1597
1598 const auto handle_data = ctx.ReadBuffer(0);
1599 const auto handle_count = ctx.GetReadBufferNumElements<Core::HID::VibrationDeviceHandle>(0);
1600 const auto vibration_data = ctx.ReadBuffer(1);
1601 const auto vibration_count = ctx.GetReadBufferNumElements<Core::HID::VibrationValue>(1);
1602
1603 auto vibration_device_handles =
1604 std::span(reinterpret_cast<const Core::HID::VibrationDeviceHandle*>(handle_data.data()),
1605 handle_count);
1606 auto vibration_values = std::span(
1607 reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
1608
1609 GetResourceManager()
1610 ->GetController<Controller_NPad>(HidController::NPad)
1611 .VibrateControllers(vibration_device_handles, vibration_values);
1612
1613 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1614
1615 IPC::ResponseBuilder rb{ctx, 2};
1616 rb.Push(ResultSuccess);
1617}
1618
1619void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
1620 IPC::RequestParser rp{ctx};
1621 struct Parameters {
1622 Core::HID::VibrationDeviceHandle vibration_device_handle;
1623 INSERT_PADDING_WORDS_NOINIT(1);
1624 u64 applet_resource_user_id;
1625 Core::HID::VibrationGcErmCommand gc_erm_command;
1626 };
1627 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1628
1629 const auto parameters{rp.PopRaw<Parameters>()};
1630
1631 /**
1632 * Note: This uses yuzu-specific behavior such that the StopHard command produces
1633 * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below,
1634 * in order to differentiate between Stop and StopHard commands.
1635 * This is done to reuse the controller vibration functions made for regular controllers.
1636 */
1637 const auto vibration_value = [parameters] {
1638 switch (parameters.gc_erm_command) {
1639 case Core::HID::VibrationGcErmCommand::Stop:
1640 return Core::HID::VibrationValue{
1641 .low_amplitude = 0.0f,
1642 .low_frequency = 160.0f,
1643 .high_amplitude = 0.0f,
1644 .high_frequency = 320.0f,
1645 };
1646 case Core::HID::VibrationGcErmCommand::Start:
1647 return Core::HID::VibrationValue{
1648 .low_amplitude = 1.0f,
1649 .low_frequency = 160.0f,
1650 .high_amplitude = 1.0f,
1651 .high_frequency = 320.0f,
1652 };
1653 case Core::HID::VibrationGcErmCommand::StopHard:
1654 return Core::HID::VibrationValue{
1655 .low_amplitude = 0.0f,
1656 .low_frequency = 0.0f,
1657 .high_amplitude = 0.0f,
1658 .high_frequency = 0.0f,
1659 };
1660 default:
1661 return Core::HID::DEFAULT_VIBRATION_VALUE;
1662 }
1663 }();
1664
1665 GetResourceManager()
1666 ->GetController<Controller_NPad>(HidController::NPad)
1667 .VibrateController(parameters.vibration_device_handle, vibration_value);
1668
1669 LOG_DEBUG(Service_HID,
1670 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
1671 "gc_erm_command={}",
1672 parameters.vibration_device_handle.npad_type,
1673 parameters.vibration_device_handle.npad_id,
1674 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
1675 parameters.gc_erm_command);
1676
1677 IPC::ResponseBuilder rb{ctx, 2};
1678 rb.Push(ResultSuccess);
1679}
1680
1681void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
1682 IPC::RequestParser rp{ctx};
1683 struct Parameters {
1684 Core::HID::VibrationDeviceHandle vibration_device_handle;
1685 INSERT_PADDING_WORDS_NOINIT(1);
1686 u64 applet_resource_user_id;
1687 };
1688
1689 const auto parameters{rp.PopRaw<Parameters>()};
1690
1691 const auto last_vibration = GetResourceManager()
1692 ->GetController<Controller_NPad>(HidController::NPad)
1693 .GetLastVibration(parameters.vibration_device_handle);
1694
1695 const auto gc_erm_command = [last_vibration] {
1696 if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
1697 return Core::HID::VibrationGcErmCommand::Start;
1698 }
1699
1700 /**
1701 * Note: This uses yuzu-specific behavior such that the StopHard command produces
1702 * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function
1703 * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
1704 * This is done to reuse the controller vibration functions made for regular controllers.
1705 */
1706 if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) {
1707 return Core::HID::VibrationGcErmCommand::StopHard;
1708 }
1709
1710 return Core::HID::VibrationGcErmCommand::Stop;
1711 }();
1712
1713 LOG_DEBUG(Service_HID,
1714 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1715 parameters.vibration_device_handle.npad_type,
1716 parameters.vibration_device_handle.npad_id,
1717 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1718
1719 IPC::ResponseBuilder rb{ctx, 4};
1720 rb.Push(ResultSuccess);
1721 rb.PushEnum(gc_erm_command);
1722}
1723
1724void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) {
1725 IPC::RequestParser rp{ctx};
1726 const auto applet_resource_user_id{rp.Pop<u64>()};
1727
1728 GetResourceManager()
1729 ->GetController<Controller_NPad>(HidController::NPad)
1730 .SetPermitVibrationSession(true);
1731
1732 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1733
1734 IPC::ResponseBuilder rb{ctx, 2};
1735 rb.Push(ResultSuccess);
1736}
1737
1738void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) {
1739 GetResourceManager()
1740 ->GetController<Controller_NPad>(HidController::NPad)
1741 .SetPermitVibrationSession(false);
1742
1743 LOG_DEBUG(Service_HID, "called");
1744
1745 IPC::ResponseBuilder rb{ctx, 2};
1746 rb.Push(ResultSuccess);
1747}
1748
1749void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) {
1750 IPC::RequestParser rp{ctx};
1751 struct Parameters {
1752 Core::HID::VibrationDeviceHandle vibration_device_handle;
1753 INSERT_PADDING_WORDS_NOINIT(1);
1754 u64 applet_resource_user_id;
1755 };
1756 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1757
1758 const auto parameters{rp.PopRaw<Parameters>()};
1759
1760 LOG_DEBUG(Service_HID,
1761 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1762 parameters.vibration_device_handle.npad_type,
1763 parameters.vibration_device_handle.npad_id,
1764 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1765
1766 IPC::ResponseBuilder rb{ctx, 3};
1767 rb.Push(ResultSuccess);
1768 rb.Push(GetResourceManager()
1769 ->GetController<Controller_NPad>(HidController::NPad)
1770 .IsVibrationDeviceMounted(parameters.vibration_device_handle));
1771}
1772
1773void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {
1774 IPC::RequestParser rp{ctx};
1775 const auto applet_resource_user_id{rp.Pop<u64>()};
1776
1777 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1778
1779 Result result = ResultSuccess;
1780 auto console_sixaxis = GetResourceManager()->GetController<Controller_ConsoleSixAxis>(
1781 HidController::ConsoleSixAxisSensor);
1782
1783 if (!firmware_settings->IsDeviceManaged()) {
1784 result = console_sixaxis.Activate();
1785 }
1786
1787 if (result.IsSuccess()) {
1788 result = console_sixaxis.Activate(applet_resource_user_id);
1789 }
1790
1791 IPC::ResponseBuilder rb{ctx, 2};
1792 rb.Push(result);
1793}
1794
1795void IHidServer::StartConsoleSixAxisSensor(HLERequestContext& ctx) {
1796 IPC::RequestParser rp{ctx};
1797 struct Parameters {
1798 Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
1799 INSERT_PADDING_WORDS_NOINIT(1);
1800 u64 applet_resource_user_id;
1801 };
1802 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1803
1804 const auto parameters{rp.PopRaw<Parameters>()};
1805
1806 LOG_WARNING(Service_HID,
1807 "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
1808 parameters.console_sixaxis_handle.unknown_1,
1809 parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
1810
1811 IPC::ResponseBuilder rb{ctx, 2};
1812 rb.Push(ResultSuccess);
1813}
1814
1815void IHidServer::StopConsoleSixAxisSensor(HLERequestContext& ctx) {
1816 IPC::RequestParser rp{ctx};
1817 struct Parameters {
1818 Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
1819 INSERT_PADDING_WORDS_NOINIT(1);
1820 u64 applet_resource_user_id;
1821 };
1822 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1823
1824 const auto parameters{rp.PopRaw<Parameters>()};
1825
1826 LOG_WARNING(Service_HID,
1827 "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
1828 parameters.console_sixaxis_handle.unknown_1,
1829 parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
1830
1831 IPC::ResponseBuilder rb{ctx, 2};
1832 rb.Push(ResultSuccess);
1833}
1834
1835void IHidServer::ActivateSevenSixAxisSensor(HLERequestContext& ctx) {
1836 IPC::RequestParser rp{ctx};
1837 const auto applet_resource_user_id{rp.Pop<u64>()};
1838
1839 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1840
1841 Result result = ResultSuccess;
1842 auto console_sixaxis = GetResourceManager()->GetController<Controller_ConsoleSixAxis>(
1843 HidController::ConsoleSixAxisSensor);
1844
1845 if (!firmware_settings->IsDeviceManaged()) {
1846 result = console_sixaxis.Activate();
1847 }
1848
1849 if (result.IsSuccess()) {
1850 console_sixaxis.Activate(applet_resource_user_id);
1851 }
1852
1853 IPC::ResponseBuilder rb{ctx, 2};
1854 rb.Push(ResultSuccess);
1855}
1856
1857void IHidServer::StartSevenSixAxisSensor(HLERequestContext& ctx) {
1858 IPC::RequestParser rp{ctx};
1859 const auto applet_resource_user_id{rp.Pop<u64>()};
1860
1861 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1862 applet_resource_user_id);
1863
1864 IPC::ResponseBuilder rb{ctx, 2};
1865 rb.Push(ResultSuccess);
1866}
1867
1868void IHidServer::StopSevenSixAxisSensor(HLERequestContext& ctx) {
1869 IPC::RequestParser rp{ctx};
1870 const auto applet_resource_user_id{rp.Pop<u64>()};
1871
1872 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1873 applet_resource_user_id);
1874
1875 IPC::ResponseBuilder rb{ctx, 2};
1876 rb.Push(ResultSuccess);
1877}
1878
1879void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
1880 IPC::RequestParser rp{ctx};
1881 const auto applet_resource_user_id{rp.Pop<u64>()};
1882 const auto t_mem_1_size{rp.Pop<u64>()};
1883 const auto t_mem_2_size{rp.Pop<u64>()};
1884 const auto t_mem_1_handle{ctx.GetCopyHandle(0)};
1885 const auto t_mem_2_handle{ctx.GetCopyHandle(1)};
1886
1887 ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
1888 ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
1889
1890 auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
1891 t_mem_1_handle);
1892
1893 if (t_mem_1.IsNull()) {
1894 LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
1895 IPC::ResponseBuilder rb{ctx, 2};
1896 rb.Push(ResultUnknown);
1897 return;
1898 }
1899
1900 auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
1901 t_mem_2_handle);
1902
1903 if (t_mem_2.IsNull()) {
1904 LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
1905 IPC::ResponseBuilder rb{ctx, 2};
1906 rb.Push(ResultUnknown);
1907 return;
1908 }
1909
1910 ASSERT_MSG(t_mem_1->GetSize() == 0x1000, "t_mem_1 has incorrect size");
1911 ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size");
1912
1913 // Activate console six axis controller
1914 GetResourceManager()
1915 ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1916 .Activate();
1917
1918 GetResourceManager()
1919 ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1920 .SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
1921
1922 LOG_WARNING(Service_HID,
1923 "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
1924 "applet_resource_user_id={}",
1925 t_mem_1_handle, t_mem_2_handle, applet_resource_user_id);
1926
1927 IPC::ResponseBuilder rb{ctx, 2};
1928 rb.Push(ResultSuccess);
1929}
1930
1931void IHidServer::FinalizeSevenSixAxisSensor(HLERequestContext& ctx) {
1932 IPC::RequestParser rp{ctx};
1933 const auto applet_resource_user_id{rp.Pop<u64>()};
1934
1935 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
1936 applet_resource_user_id);
1937
1938 IPC::ResponseBuilder rb{ctx, 2};
1939 rb.Push(ResultSuccess);
1940}
1941
1942void IHidServer::ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx) {
1943 IPC::RequestParser rp{ctx};
1944 const auto applet_resource_user_id{rp.Pop<u64>()};
1945
1946 GetResourceManager()
1947 ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
1948 .ResetTimestamp();
1949
1950 LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
1951
1952 IPC::ResponseBuilder rb{ctx, 2};
1953 rb.Push(ResultSuccess);
1954}
1955
1956void IHidServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
1957 IPC::RequestParser rp{ctx};
1958
1959 LOG_WARNING(Service_HID, "(STUBBED) called");
1960
1961 IPC::ResponseBuilder rb{ctx, 3};
1962 rb.Push(ResultSuccess);
1963 rb.Push(false);
1964}
1965
1966void IHidServer::GetPalmaConnectionHandle(HLERequestContext& ctx) {
1967 IPC::RequestParser rp{ctx};
1968 struct Parameters {
1969 Core::HID::NpadIdType npad_id;
1970 INSERT_PADDING_WORDS_NOINIT(1);
1971 u64 applet_resource_user_id;
1972 };
1973 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
1974
1975 const auto parameters{rp.PopRaw<Parameters>()};
1976
1977 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
1978 parameters.npad_id, parameters.applet_resource_user_id);
1979
1980 Controller_Palma::PalmaConnectionHandle handle;
1981 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
1982 const auto result = controller.GetPalmaConnectionHandle(parameters.npad_id, handle);
1983
1984 IPC::ResponseBuilder rb{ctx, 4};
1985 rb.Push(result);
1986 rb.PushRaw(handle);
1987}
1988
1989void IHidServer::InitializePalma(HLERequestContext& ctx) {
1990 IPC::RequestParser rp{ctx};
1991 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
1992
1993 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
1994
1995 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
1996 const auto result = controller.InitializePalma(connection_handle);
1997
1998 IPC::ResponseBuilder rb{ctx, 2};
1999 rb.Push(result);
2000}
2001
2002void IHidServer::AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx) {
2003 IPC::RequestParser rp{ctx};
2004 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2005
2006 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2007
2008 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
2009
2010 IPC::ResponseBuilder rb{ctx, 2, 1};
2011 rb.Push(ResultSuccess);
2012 rb.PushCopyObjects(controller.AcquirePalmaOperationCompleteEvent(connection_handle));
2013}
2014
2015void IHidServer::GetPalmaOperationInfo(HLERequestContext& ctx) {
2016 IPC::RequestParser rp{ctx};
2017 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2018
2019 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2020
2021 Controller_Palma::PalmaOperationType operation_type;
2022 Controller_Palma::PalmaOperationData data;
2023 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
2024 const auto result = controller.GetPalmaOperationInfo(connection_handle, operation_type, data);
2025
2026 if (result.IsError()) {
2027 IPC::ResponseBuilder rb{ctx, 2};
2028 rb.Push(result);
2029 }
2030
2031 ctx.WriteBuffer(data);
2032 IPC::ResponseBuilder rb{ctx, 4};
2033 rb.Push(result);
2034 rb.Push(static_cast<u64>(operation_type));
2035}
2036
2037void IHidServer::PlayPalmaActivity(HLERequestContext& ctx) {
2038 IPC::RequestParser rp{ctx};
2039 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2040 const auto palma_activity{rp.Pop<u64>()};
2041
2042 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, palma_activity={}",
2043 connection_handle.npad_id, palma_activity);
2044
2045 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
2046 const auto result = controller.PlayPalmaActivity(connection_handle, palma_activity);
2047
2048 IPC::ResponseBuilder rb{ctx, 2};
2049 rb.Push(result);
2050}
2051
2052void IHidServer::SetPalmaFrModeType(HLERequestContext& ctx) {
2053 IPC::RequestParser rp{ctx};
2054 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2055 const auto fr_mode{rp.PopEnum<Controller_Palma::PalmaFrModeType>()};
2056
2057 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, fr_mode={}",
2058 connection_handle.npad_id, fr_mode);
2059
2060 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
2061 const auto result = controller.SetPalmaFrModeType(connection_handle, fr_mode);
2062
2063 IPC::ResponseBuilder rb{ctx, 2};
2064 rb.Push(result);
2065}
2066
2067void IHidServer::ReadPalmaStep(HLERequestContext& ctx) {
2068 IPC::RequestParser rp{ctx};
2069 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2070
2071 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2072
2073 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
2074 const auto result = controller.ReadPalmaStep(connection_handle);
2075
2076 IPC::ResponseBuilder rb{ctx, 2};
2077 rb.Push(result);
2078}
2079
2080void IHidServer::EnablePalmaStep(HLERequestContext& ctx) {
2081 IPC::RequestParser rp{ctx};
2082 struct Parameters {
2083 bool is_enabled;
2084 INSERT_PADDING_WORDS_NOINIT(1);
2085 Controller_Palma::PalmaConnectionHandle connection_handle;
2086 };
2087 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2088
2089 const auto parameters{rp.PopRaw<Parameters>()};
2090
2091 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, is_enabled={}",
2092 parameters.connection_handle.npad_id, parameters.is_enabled);
2093
2094 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
2095 const auto result =
2096 controller.EnablePalmaStep(parameters.connection_handle, parameters.is_enabled);
2097
2098 IPC::ResponseBuilder rb{ctx, 2};
2099 rb.Push(result);
2100}
2101
2102void IHidServer::ResetPalmaStep(HLERequestContext& ctx) {
2103 IPC::RequestParser rp{ctx};
2104 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2105
2106 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2107
2108 auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
2109 const auto result = controller.ResetPalmaStep(connection_handle);
2110
2111 IPC::ResponseBuilder rb{ctx, 2};
2112 rb.Push(result);
2113}
2114
2115void IHidServer::ReadPalmaApplicationSection(HLERequestContext& ctx) {
2116 LOG_WARNING(Service_HID, "(STUBBED) called");
2117
2118 IPC::ResponseBuilder rb{ctx, 2};
2119 rb.Push(ResultSuccess);
2120}
2121
2122void IHidServer::WritePalmaApplicationSection(HLERequestContext& ctx) {
2123 LOG_WARNING(Service_HID, "(STUBBED) called");
2124
2125 IPC::ResponseBuilder rb{ctx, 2};
2126 rb.Push(ResultSuccess);
2127}
2128
2129void IHidServer::ReadPalmaUniqueCode(HLERequestContext& ctx) {
2130 IPC::RequestParser rp{ctx};
2131 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2132
2133 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2134
2135 GetResourceManager()
2136 ->GetController<Controller_Palma>(HidController::Palma)
2137 .ReadPalmaUniqueCode(connection_handle);
2138
2139 IPC::ResponseBuilder rb{ctx, 2};
2140 rb.Push(ResultSuccess);
2141}
2142
2143void IHidServer::SetPalmaUniqueCodeInvalid(HLERequestContext& ctx) {
2144 IPC::RequestParser rp{ctx};
2145 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2146
2147 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2148
2149 GetResourceManager()
2150 ->GetController<Controller_Palma>(HidController::Palma)
2151 .SetPalmaUniqueCodeInvalid(connection_handle);
2152
2153 IPC::ResponseBuilder rb{ctx, 2};
2154 rb.Push(ResultSuccess);
2155}
2156
2157void IHidServer::WritePalmaActivityEntry(HLERequestContext& ctx) {
2158 LOG_CRITICAL(Service_HID, "(STUBBED) called");
2159
2160 IPC::ResponseBuilder rb{ctx, 2};
2161 rb.Push(ResultSuccess);
2162}
2163
2164void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) {
2165 IPC::RequestParser rp{ctx};
2166 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2167 const auto unknown{rp.Pop<u64>()};
2168
2169 [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
2170
2171 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
2172 connection_handle.npad_id, unknown);
2173
2174 GetResourceManager()
2175 ->GetController<Controller_Palma>(HidController::Palma)
2176 .WritePalmaRgbLedPatternEntry(connection_handle, unknown);
2177
2178 IPC::ResponseBuilder rb{ctx, 2};
2179 rb.Push(ResultSuccess);
2180}
2181
2182void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
2183 IPC::RequestParser rp{ctx};
2184 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2185 const auto wave_set{rp.PopEnum<Controller_Palma::PalmaWaveSet>()};
2186 const auto unknown{rp.Pop<u64>()};
2187 const auto t_mem_size{rp.Pop<u64>()};
2188 const auto t_mem_handle{ctx.GetCopyHandle(0)};
2189 const auto size{rp.Pop<u64>()};
2190
2191 ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
2192
2193 auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
2194 t_mem_handle);
2195
2196 if (t_mem.IsNull()) {
2197 LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
2198 IPC::ResponseBuilder rb{ctx, 2};
2199 rb.Push(ResultUnknown);
2200 return;
2201 }
2202
2203 ASSERT_MSG(t_mem->GetSize() == 0x3000, "t_mem has incorrect size");
2204
2205 LOG_WARNING(Service_HID,
2206 "(STUBBED) called, connection_handle={}, wave_set={}, unknown={}, "
2207 "t_mem_handle=0x{:08X}, t_mem_size={}, size={}",
2208 connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size);
2209
2210 GetResourceManager()
2211 ->GetController<Controller_Palma>(HidController::Palma)
2212 .WritePalmaWaveEntry(connection_handle, wave_set, t_mem->GetSourceAddress(), t_mem_size);
2213
2214 IPC::ResponseBuilder rb{ctx, 2};
2215 rb.Push(ResultSuccess);
2216}
2217
2218void IHidServer::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
2219 IPC::RequestParser rp{ctx};
2220 struct Parameters {
2221 s32 database_id_version;
2222 INSERT_PADDING_WORDS_NOINIT(1);
2223 Controller_Palma::PalmaConnectionHandle connection_handle;
2224 };
2225 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2226
2227 const auto parameters{rp.PopRaw<Parameters>()};
2228
2229 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, database_id_version={}",
2230 parameters.connection_handle.npad_id, parameters.database_id_version);
2231
2232 GetResourceManager()
2233 ->GetController<Controller_Palma>(HidController::Palma)
2234 .SetPalmaDataBaseIdentificationVersion(parameters.connection_handle,
2235 parameters.database_id_version);
2236
2237 IPC::ResponseBuilder rb{ctx, 2};
2238 rb.Push(ResultSuccess);
2239}
2240
2241void IHidServer::GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
2242 IPC::RequestParser rp{ctx};
2243 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2244
2245 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2246
2247 GetResourceManager()
2248 ->GetController<Controller_Palma>(HidController::Palma)
2249 .GetPalmaDataBaseIdentificationVersion(connection_handle);
2250
2251 IPC::ResponseBuilder rb{ctx, 2};
2252 rb.Push(ResultSuccess);
2253}
2254
2255void IHidServer::SuspendPalmaFeature(HLERequestContext& ctx) {
2256 LOG_WARNING(Service_HID, "(STUBBED) called");
2257
2258 IPC::ResponseBuilder rb{ctx, 2};
2259 rb.Push(ResultSuccess);
2260}
2261
2262void IHidServer::GetPalmaOperationResult(HLERequestContext& ctx) {
2263 IPC::RequestParser rp{ctx};
2264 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2265
2266 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2267
2268 const auto result = GetResourceManager()
2269 ->GetController<Controller_Palma>(HidController::Palma)
2270 .GetPalmaOperationResult(connection_handle);
2271
2272 IPC::ResponseBuilder rb{ctx, 2};
2273 rb.Push(result);
2274}
2275
2276void IHidServer::ReadPalmaPlayLog(HLERequestContext& ctx) {
2277 LOG_WARNING(Service_HID, "(STUBBED) called");
2278
2279 IPC::ResponseBuilder rb{ctx, 2};
2280 rb.Push(ResultSuccess);
2281}
2282
2283void IHidServer::ResetPalmaPlayLog(HLERequestContext& ctx) {
2284 LOG_WARNING(Service_HID, "(STUBBED) called");
2285
2286 IPC::ResponseBuilder rb{ctx, 2};
2287 rb.Push(ResultSuccess);
2288}
2289
2290void IHidServer::SetIsPalmaAllConnectable(HLERequestContext& ctx) {
2291 IPC::RequestParser rp{ctx};
2292 struct Parameters {
2293 bool is_palma_all_connectable;
2294 INSERT_PADDING_BYTES_NOINIT(7);
2295 u64 applet_resource_user_id;
2296 };
2297 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2298
2299 const auto parameters{rp.PopRaw<Parameters>()};
2300
2301 LOG_WARNING(Service_HID,
2302 "(STUBBED) called, is_palma_all_connectable={},applet_resource_user_id={}",
2303 parameters.is_palma_all_connectable, parameters.applet_resource_user_id);
2304
2305 GetResourceManager()
2306 ->GetController<Controller_Palma>(HidController::Palma)
2307 .SetIsPalmaAllConnectable(parameters.is_palma_all_connectable);
2308
2309 IPC::ResponseBuilder rb{ctx, 2};
2310 rb.Push(ResultSuccess);
2311}
2312
2313void IHidServer::SetIsPalmaPairedConnectable(HLERequestContext& ctx) {
2314 LOG_WARNING(Service_HID, "(STUBBED) called");
2315
2316 IPC::ResponseBuilder rb{ctx, 2};
2317 rb.Push(ResultSuccess);
2318}
2319
2320void IHidServer::PairPalma(HLERequestContext& ctx) {
2321 IPC::RequestParser rp{ctx};
2322 const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
2323
2324 LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
2325
2326 GetResourceManager()
2327 ->GetController<Controller_Palma>(HidController::Palma)
2328 .PairPalma(connection_handle);
2329
2330 IPC::ResponseBuilder rb{ctx, 2};
2331 rb.Push(ResultSuccess);
2332}
2333
2334void IHidServer::SetPalmaBoostMode(HLERequestContext& ctx) {
2335 IPC::RequestParser rp{ctx};
2336 const auto palma_boost_mode{rp.Pop<bool>()};
2337
2338 LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode);
2339
2340 GetResourceManager()
2341 ->GetController<Controller_Palma>(HidController::Palma)
2342 .SetPalmaBoostMode(palma_boost_mode);
2343
2344 IPC::ResponseBuilder rb{ctx, 2};
2345 rb.Push(ResultSuccess);
2346}
2347
2348void IHidServer::CancelWritePalmaWaveEntry(HLERequestContext& ctx) {
2349 LOG_WARNING(Service_HID, "(STUBBED) called");
2350
2351 IPC::ResponseBuilder rb{ctx, 2};
2352 rb.Push(ResultSuccess);
2353}
2354
2355void IHidServer::EnablePalmaBoostMode(HLERequestContext& ctx) {
2356 LOG_WARNING(Service_HID, "(STUBBED) called");
2357
2358 IPC::ResponseBuilder rb{ctx, 2};
2359 rb.Push(ResultSuccess);
2360}
2361
2362void IHidServer::GetPalmaBluetoothAddress(HLERequestContext& ctx) {
2363 LOG_WARNING(Service_HID, "(STUBBED) called");
2364
2365 IPC::ResponseBuilder rb{ctx, 2};
2366 rb.Push(ResultSuccess);
2367}
2368
2369void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
2370 LOG_WARNING(Service_HID, "(STUBBED) called");
2371
2372 IPC::ResponseBuilder rb{ctx, 2};
2373 rb.Push(ResultSuccess);
2374}
2375
2376void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) {
2377 IPC::RequestParser rp{ctx};
2378 const auto applet_resource_user_id{rp.Pop<u64>()};
2379 const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()};
2380
2381 GetResourceManager()
2382 ->GetController<Controller_NPad>(HidController::NPad)
2383 .SetNpadCommunicationMode(communication_mode);
2384
2385 LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}",
2386 applet_resource_user_id, communication_mode);
2387
2388 IPC::ResponseBuilder rb{ctx, 2};
2389 rb.Push(ResultSuccess);
2390}
2391
2392void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) {
2393 IPC::RequestParser rp{ctx};
2394
2395 LOG_WARNING(Service_HID, "(STUBBED) called");
2396
2397 IPC::ResponseBuilder rb{ctx, 4};
2398 rb.Push(ResultSuccess);
2399 rb.PushEnum(GetResourceManager()
2400 ->GetController<Controller_NPad>(HidController::NPad)
2401 .GetNpadCommunicationMode());
2402}
2403
2404void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) {
2405 IPC::RequestParser rp{ctx};
2406 const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};
2407 const auto applet_resource_user_id{rp.Pop<u64>()};
2408
2409 LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}",
2410 touchscreen_mode.mode, applet_resource_user_id);
2411
2412 IPC::ResponseBuilder rb{ctx, 2};
2413 rb.Push(ResultSuccess);
2414}
2415
2416void IHidServer::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) {
2417 IPC::RequestParser rp{ctx};
2418 struct Parameters {
2419 s32 unknown;
2420 INSERT_PADDING_WORDS_NOINIT(1);
2421 u64 applet_resource_user_id;
2422 };
2423 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
2424
2425 const auto parameters{rp.PopRaw<Parameters>()};
2426
2427 LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}",
2428 parameters.unknown, parameters.applet_resource_user_id);
2429
2430 IPC::ResponseBuilder rb{ctx, 3};
2431 rb.Push(ResultSuccess);
2432 rb.Push(false);
2433}
2434
2435std::shared_ptr<ResourceManager> IHidServer::GetResourceManager() {
2436 resource_manager->Initialize();
2437 return resource_manager;
2438}
2439
2440} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h
new file mode 100644
index 000000000..eb2e8e7f4
--- /dev/null
+++ b/src/core/hle/service/hid/hid_server.h
@@ -0,0 +1,149 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Core {
9class System;
10}
11
12namespace Service::HID {
13class ResourceManager;
14class HidFirmwareSettings;
15
16class IHidServer final : public ServiceFramework<IHidServer> {
17public:
18 explicit IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
19 std::shared_ptr<HidFirmwareSettings> settings);
20 ~IHidServer() override;
21
22 std::shared_ptr<ResourceManager> GetResourceManager();
23
24private:
25 void CreateAppletResource(HLERequestContext& ctx);
26 void ActivateDebugPad(HLERequestContext& ctx);
27 void ActivateTouchScreen(HLERequestContext& ctx);
28 void ActivateMouse(HLERequestContext& ctx);
29 void ActivateKeyboard(HLERequestContext& ctx);
30 void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
31 void AcquireXpadIdEventHandle(HLERequestContext& ctx);
32 void ReleaseXpadIdEventHandle(HLERequestContext& ctx);
33 void ActivateXpad(HLERequestContext& ctx);
34 void GetXpadIds(HLERequestContext& ctx);
35 void ActivateJoyXpad(HLERequestContext& ctx);
36 void GetJoyXpadLifoHandle(HLERequestContext& ctx);
37 void GetJoyXpadIds(HLERequestContext& ctx);
38 void ActivateSixAxisSensor(HLERequestContext& ctx);
39 void DeactivateSixAxisSensor(HLERequestContext& ctx);
40 void GetSixAxisSensorLifoHandle(HLERequestContext& ctx);
41 void ActivateJoySixAxisSensor(HLERequestContext& ctx);
42 void DeactivateJoySixAxisSensor(HLERequestContext& ctx);
43 void GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx);
44 void StartSixAxisSensor(HLERequestContext& ctx);
45 void StopSixAxisSensor(HLERequestContext& ctx);
46 void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
47 void EnableSixAxisSensorFusion(HLERequestContext& ctx);
48 void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
49 void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
50 void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
51 void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
52 void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
53 void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
54 void IsSixAxisSensorAtRest(HLERequestContext& ctx);
55 void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
56 void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
57 void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
58 void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
59 void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
60 void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
61 void ActivateGesture(HLERequestContext& ctx);
62 void SetSupportedNpadStyleSet(HLERequestContext& ctx);
63 void GetSupportedNpadStyleSet(HLERequestContext& ctx);
64 void SetSupportedNpadIdType(HLERequestContext& ctx);
65 void ActivateNpad(HLERequestContext& ctx);
66 void DeactivateNpad(HLERequestContext& ctx);
67 void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
68 void DisconnectNpad(HLERequestContext& ctx);
69 void GetPlayerLedPattern(HLERequestContext& ctx);
70 void ActivateNpadWithRevision(HLERequestContext& ctx);
71 void SetNpadJoyHoldType(HLERequestContext& ctx);
72 void GetNpadJoyHoldType(HLERequestContext& ctx);
73 void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
74 void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
75 void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
76 void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
77 void StartLrAssignmentMode(HLERequestContext& ctx);
78 void StopLrAssignmentMode(HLERequestContext& ctx);
79 void SetNpadHandheldActivationMode(HLERequestContext& ctx);
80 void GetNpadHandheldActivationMode(HLERequestContext& ctx);
81 void SwapNpadAssignment(HLERequestContext& ctx);
82 void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
83 void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
84 void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
85 void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
86 void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
87 void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
88 void GetVibrationDeviceInfo(HLERequestContext& ctx);
89 void SendVibrationValue(HLERequestContext& ctx);
90 void GetActualVibrationValue(HLERequestContext& ctx);
91 void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
92 void PermitVibration(HLERequestContext& ctx);
93 void IsVibrationPermitted(HLERequestContext& ctx);
94 void SendVibrationValues(HLERequestContext& ctx);
95 void SendVibrationGcErmCommand(HLERequestContext& ctx);
96 void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
97 void BeginPermitVibrationSession(HLERequestContext& ctx);
98 void EndPermitVibrationSession(HLERequestContext& ctx);
99 void IsVibrationDeviceMounted(HLERequestContext& ctx);
100 void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
101 void StartConsoleSixAxisSensor(HLERequestContext& ctx);
102 void StopConsoleSixAxisSensor(HLERequestContext& ctx);
103 void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
104 void StartSevenSixAxisSensor(HLERequestContext& ctx);
105 void StopSevenSixAxisSensor(HLERequestContext& ctx);
106 void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
107 void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
108 void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
109 void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
110 void GetPalmaConnectionHandle(HLERequestContext& ctx);
111 void InitializePalma(HLERequestContext& ctx);
112 void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
113 void GetPalmaOperationInfo(HLERequestContext& ctx);
114 void PlayPalmaActivity(HLERequestContext& ctx);
115 void SetPalmaFrModeType(HLERequestContext& ctx);
116 void ReadPalmaStep(HLERequestContext& ctx);
117 void EnablePalmaStep(HLERequestContext& ctx);
118 void ResetPalmaStep(HLERequestContext& ctx);
119 void ReadPalmaApplicationSection(HLERequestContext& ctx);
120 void WritePalmaApplicationSection(HLERequestContext& ctx);
121 void ReadPalmaUniqueCode(HLERequestContext& ctx);
122 void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
123 void WritePalmaActivityEntry(HLERequestContext& ctx);
124 void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
125 void WritePalmaWaveEntry(HLERequestContext& ctx);
126 void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
127 void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
128 void SuspendPalmaFeature(HLERequestContext& ctx);
129 void GetPalmaOperationResult(HLERequestContext& ctx);
130 void ReadPalmaPlayLog(HLERequestContext& ctx);
131 void ResetPalmaPlayLog(HLERequestContext& ctx);
132 void SetIsPalmaAllConnectable(HLERequestContext& ctx);
133 void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
134 void PairPalma(HLERequestContext& ctx);
135 void SetPalmaBoostMode(HLERequestContext& ctx);
136 void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
137 void EnablePalmaBoostMode(HLERequestContext& ctx);
138 void GetPalmaBluetoothAddress(HLERequestContext& ctx);
139 void SetDisallowedPalmaConnection(HLERequestContext& ctx);
140 void SetNpadCommunicationMode(HLERequestContext& ctx);
141 void GetNpadCommunicationMode(HLERequestContext& ctx);
142 void SetTouchScreenConfiguration(HLERequestContext& ctx);
143 void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
144
145 std::shared_ptr<ResourceManager> resource_manager;
146 std::shared_ptr<HidFirmwareSettings> firmware_settings;
147};
148
149} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
new file mode 100644
index 000000000..83cfadada
--- /dev/null
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -0,0 +1,304 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hid/hid_core.h"
5#include "core/hle/service/hid/controllers/npad.h"
6#include "core/hle/service/hid/controllers/touchscreen.h"
7#include "core/hle/service/hid/errors.h"
8#include "core/hle/service/hid/hid_system_server.h"
9#include "core/hle/service/hid/resource_manager.h"
10#include "core/hle/service/ipc_helpers.h"
11
12namespace Service::HID {
13
14IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
15 : ServiceFramework{system_, "hid:sys"}, service_context{system_, service_name},
16 resource_manager{resource} {
17 // clang-format off
18 static const FunctionInfo functions[] = {
19 {31, nullptr, "SendKeyboardLockKeyEvent"},
20 {101, nullptr, "AcquireHomeButtonEventHandle"},
21 {111, nullptr, "ActivateHomeButton"},
22 {121, nullptr, "AcquireSleepButtonEventHandle"},
23 {131, nullptr, "ActivateSleepButton"},
24 {141, nullptr, "AcquireCaptureButtonEventHandle"},
25 {151, nullptr, "ActivateCaptureButton"},
26 {161, nullptr, "GetPlatformConfig"},
27 {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
28 {211, nullptr, "GetNpadsWithNfc"},
29 {212, nullptr, "AcquireNfcActivateEventHandle"},
30 {213, nullptr, "ActivateNfc"},
31 {214, nullptr, "GetXcdHandleForNpadWithNfc"},
32 {215, nullptr, "IsNfcActivated"},
33 {230, nullptr, "AcquireIrSensorEventHandle"},
34 {231, nullptr, "ActivateIrSensor"},
35 {232, nullptr, "GetIrSensorState"},
36 {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
37 {301, nullptr, "ActivateNpadSystem"},
38 {303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
39 {304, nullptr, "EnableAssigningSingleOnSlSrPress"},
40 {305, nullptr, "DisableAssigningSingleOnSlSrPress"},
41 {306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"},
42 {307, nullptr, "GetNpadSystemExtStyle"},
43 {308, nullptr, "ApplyNpadSystemCommonPolicyFull"},
44 {309, nullptr, "GetNpadFullKeyGripColor"},
45 {310, nullptr, "GetMaskedSupportedNpadStyleSet"},
46 {311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
47 {312, nullptr, "SetSupportedNpadStyleSetAll"},
48 {313, nullptr, "GetNpadCaptureButtonAssignment"},
49 {314, nullptr, "GetAppletFooterUiType"},
50 {315, nullptr, "GetAppletDetailedUiType"},
51 {316, nullptr, "GetNpadInterfaceType"},
52 {317, nullptr, "GetNpadLeftRightInterfaceType"},
53 {318, nullptr, "HasBattery"},
54 {319, nullptr, "HasLeftRightBattery"},
55 {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
56 {322, nullptr, "GetIrSensorState"},
57 {323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
58 {324, nullptr, "GetUniquePadButtonSet"},
59 {325, nullptr, "GetUniquePadColor"},
60 {326, nullptr, "GetUniquePadAppletDetailedUiType"},
61 {327, nullptr, "GetAbstractedPadIdDataFromNpad"},
62 {328, nullptr, "AttachAbstractedPadToNpad"},
63 {329, nullptr, "DetachAbstractedPadAll"},
64 {330, nullptr, "CheckAbstractedPadConnection"},
65 {500, nullptr, "SetAppletResourceUserId"},
66 {501, nullptr, "RegisterAppletResourceUserId"},
67 {502, nullptr, "UnregisterAppletResourceUserId"},
68 {503, nullptr, "EnableAppletToGetInput"},
69 {504, nullptr, "SetAruidValidForVibration"},
70 {505, nullptr, "EnableAppletToGetSixAxisSensor"},
71 {506, nullptr, "EnableAppletToGetPadInput"},
72 {507, nullptr, "EnableAppletToGetTouchScreen"},
73 {510, nullptr, "SetVibrationMasterVolume"},
74 {511, nullptr, "GetVibrationMasterVolume"},
75 {512, nullptr, "BeginPermitVibrationSession"},
76 {513, nullptr, "EndPermitVibrationSession"},
77 {514, nullptr, "Unknown514"},
78 {520, nullptr, "EnableHandheldHids"},
79 {521, nullptr, "DisableHandheldHids"},
80 {522, nullptr, "SetJoyConRailEnabled"},
81 {523, nullptr, "IsJoyConRailEnabled"},
82 {524, nullptr, "IsHandheldHidsEnabled"},
83 {525, nullptr, "IsJoyConAttachedOnAllRail"},
84 {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
85 {541, nullptr, "GetPlayReportControllerUsages"},
86 {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
87 {543, nullptr, "GetRegisteredDevicesOld"},
88 {544, nullptr, "AcquireConnectionTriggerTimeoutEvent"},
89 {545, nullptr, "SendConnectionTrigger"},
90 {546, nullptr, "AcquireDeviceRegisteredEventForControllerSupport"},
91 {547, nullptr, "GetAllowedBluetoothLinksCount"},
92 {548, nullptr, "GetRegisteredDevices"},
93 {549, nullptr, "GetConnectableRegisteredDevices"},
94 {700, nullptr, "ActivateUniquePad"},
95 {702, nullptr, "AcquireUniquePadConnectionEventHandle"},
96 {703, nullptr, "GetUniquePadIds"},
97 {751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
98 {800, nullptr, "ListSixAxisSensorHandles"},
99 {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
100 {802, nullptr, "ResetSixAxisSensorCalibrationValues"},
101 {803, nullptr, "StartSixAxisSensorUserCalibration"},
102 {804, nullptr, "CancelSixAxisSensorUserCalibration"},
103 {805, nullptr, "GetUniquePadBluetoothAddress"},
104 {806, nullptr, "DisconnectUniquePad"},
105 {807, nullptr, "GetUniquePadType"},
106 {808, nullptr, "GetUniquePadInterface"},
107 {809, nullptr, "GetUniquePadSerialNumber"},
108 {810, nullptr, "GetUniquePadControllerNumber"},
109 {811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
110 {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
111 {821, nullptr, "StartAnalogStickManualCalibration"},
112 {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
113 {823, nullptr, "CancelAnalogStickManualCalibration"},
114 {824, nullptr, "ResetAnalogStickManualCalibration"},
115 {825, nullptr, "GetAnalogStickState"},
116 {826, nullptr, "GetAnalogStickManualCalibrationStage"},
117 {827, nullptr, "IsAnalogStickButtonPressed"},
118 {828, nullptr, "IsAnalogStickInReleasePosition"},
119 {829, nullptr, "IsAnalogStickInCircumference"},
120 {830, nullptr, "SetNotificationLedPattern"},
121 {831, nullptr, "SetNotificationLedPatternWithTimeout"},
122 {832, nullptr, "PrepareHidsForNotificationWake"},
123 {850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
124 {851, nullptr, "EnableUsbFullKeyController"},
125 {852, nullptr, "IsUsbConnected"},
126 {870, nullptr, "IsHandheldButtonPressedOnConsoleMode"},
127 {900, nullptr, "ActivateInputDetector"},
128 {901, nullptr, "NotifyInputDetector"},
129 {1000, nullptr, "InitializeFirmwareUpdate"},
130 {1001, nullptr, "GetFirmwareVersion"},
131 {1002, nullptr, "GetAvailableFirmwareVersion"},
132 {1003, nullptr, "IsFirmwareUpdateAvailable"},
133 {1004, nullptr, "CheckFirmwareUpdateRequired"},
134 {1005, nullptr, "StartFirmwareUpdate"},
135 {1006, nullptr, "AbortFirmwareUpdate"},
136 {1007, nullptr, "GetFirmwareUpdateState"},
137 {1008, nullptr, "ActivateAudioControl"},
138 {1009, nullptr, "AcquireAudioControlEventHandle"},
139 {1010, nullptr, "GetAudioControlStates"},
140 {1011, nullptr, "DeactivateAudioControl"},
141 {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
142 {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
143 {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
144 {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
145 {1100, nullptr, "GetHidbusSystemServiceObject"},
146 {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
147 {1130, nullptr, "InitializeUsbFirmwareUpdate"},
148 {1131, nullptr, "FinalizeUsbFirmwareUpdate"},
149 {1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
150 {1133, nullptr, "StartUsbFirmwareUpdate"},
151 {1134, nullptr, "GetUsbFirmwareUpdateState"},
152 {1150, nullptr, "SetTouchScreenMagnification"},
153 {1151, nullptr, "GetTouchScreenFirmwareVersion"},
154 {1152, nullptr, "SetTouchScreenDefaultConfiguration"},
155 {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
156 {1154, nullptr, "IsFirmwareAvailableForNotification"},
157 {1155, nullptr, "SetForceHandheldStyleVibration"},
158 {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
159 {1157, nullptr, "CancelConnectionTrigger"},
160 {1200, nullptr, "IsButtonConfigSupported"},
161 {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
162 {1202, nullptr, "DeleteButtonConfig"},
163 {1203, nullptr, "DeleteButtonConfigEmbedded"},
164 {1204, nullptr, "SetButtonConfigEnabled"},
165 {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
166 {1206, nullptr, "IsButtonConfigEnabled"},
167 {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
168 {1208, nullptr, "SetButtonConfigEmbedded"},
169 {1209, nullptr, "SetButtonConfigFull"},
170 {1210, nullptr, "SetButtonConfigLeft"},
171 {1211, nullptr, "SetButtonConfigRight"},
172 {1212, nullptr, "GetButtonConfigEmbedded"},
173 {1213, nullptr, "GetButtonConfigFull"},
174 {1214, nullptr, "GetButtonConfigLeft"},
175 {1215, nullptr, "GetButtonConfigRight"},
176 {1250, nullptr, "IsCustomButtonConfigSupported"},
177 {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
178 {1252, nullptr, "IsDefaultButtonConfigFull"},
179 {1253, nullptr, "IsDefaultButtonConfigLeft"},
180 {1254, nullptr, "IsDefaultButtonConfigRight"},
181 {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
182 {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
183 {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
184 {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
185 {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
186 {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
187 {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
188 {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
189 {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
190 {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
191 {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
192 {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
193 {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
194 {1268, nullptr, "DeleteButtonConfigStorageFull"},
195 {1269, nullptr, "DeleteButtonConfigStorageLeft"},
196 {1270, nullptr, "DeleteButtonConfigStorageRight"},
197 {1271, nullptr, "IsUsingCustomButtonConfig"},
198 {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
199 {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
200 {1274, nullptr, "SetDefaultButtonConfig"},
201 {1275, nullptr, "SetAllDefaultButtonConfig"},
202 {1276, nullptr, "SetHidButtonConfigEmbedded"},
203 {1277, nullptr, "SetHidButtonConfigFull"},
204 {1278, nullptr, "SetHidButtonConfigLeft"},
205 {1279, nullptr, "SetHidButtonConfigRight"},
206 {1280, nullptr, "GetHidButtonConfigEmbedded"},
207 {1281, nullptr, "GetHidButtonConfigFull"},
208 {1282, nullptr, "GetHidButtonConfigLeft"},
209 {1283, nullptr, "GetHidButtonConfigRight"},
210 {1284, nullptr, "GetButtonConfigStorageEmbedded"},
211 {1285, nullptr, "GetButtonConfigStorageFull"},
212 {1286, nullptr, "GetButtonConfigStorageLeft"},
213 {1287, nullptr, "GetButtonConfigStorageRight"},
214 {1288, nullptr, "SetButtonConfigStorageEmbedded"},
215 {1289, nullptr, "SetButtonConfigStorageFull"},
216 {1290, nullptr, "DeleteButtonConfigStorageRight"},
217 {1291, nullptr, "DeleteButtonConfigStorageRight"},
218 };
219 // clang-format on
220
221 RegisterHandlers(functions);
222
223 joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent");
224}
225
226IHidSystemServer::~IHidSystemServer() {
227 service_context.CloseEvent(joy_detach_event);
228};
229
230void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
231 LOG_WARNING(Service_HID, "called");
232
233 GetResourceManager()
234 ->GetController<Controller_NPad>(HidController::NPad)
235 .ApplyNpadSystemCommonPolicy();
236
237 IPC::ResponseBuilder rb{ctx, 2};
238 rb.Push(ResultSuccess);
239}
240
241void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
242 LOG_DEBUG(Service_HID, "(STUBBED) called");
243
244 IPC::ResponseBuilder rb{ctx, 3};
245 rb.Push(ResultSuccess);
246 rb.PushEnum(system.HIDCore().GetLastActiveController());
247}
248
249void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) {
250 IPC::RequestParser rp{ctx};
251 const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
252
253 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type);
254
255 const std::vector<Core::HID::UniquePadId> unique_pads{};
256
257 ctx.WriteBuffer(unique_pads);
258
259 IPC::ResponseBuilder rb{ctx, 3};
260 rb.Push(ResultSuccess);
261 rb.Push(static_cast<u32>(unique_pads.size()));
262}
263
264void IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
265 LOG_INFO(Service_AM, "called");
266
267 IPC::ResponseBuilder rb{ctx, 2, 1};
268 rb.Push(ResultSuccess);
269 rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
270}
271
272void IHidSystemServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
273 const bool is_enabled = false;
274
275 LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
276
277 IPC::ResponseBuilder rb{ctx, 3};
278 rb.Push(ResultSuccess);
279 rb.Push(is_enabled);
280}
281
282void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
283 LOG_WARNING(Service_HID, "(STUBBED) called");
284
285 Core::HID::TouchScreenConfigurationForNx touchscreen_config{
286 .mode = Core::HID::TouchScreenModeForNx::Finger,
287 };
288
289 if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
290 touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
291 touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
292 }
293
294 IPC::ResponseBuilder rb{ctx, 6};
295 rb.Push(ResultSuccess);
296 rb.PushRaw(touchscreen_config);
297}
298
299std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
300 resource_manager->Initialize();
301 return resource_manager;
302}
303
304} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h
new file mode 100644
index 000000000..d4b3910fa
--- /dev/null
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Kernel {
14class KEvent;
15}
16
17namespace Service::HID {
18class ResourceManager;
19
20class IHidSystemServer final : public ServiceFramework<IHidSystemServer> {
21public:
22 explicit IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
23 ~IHidSystemServer() override;
24
25private:
26 void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx);
27 void GetLastActiveNpad(HLERequestContext& ctx);
28 void GetUniquePadsFromNpad(HLERequestContext& ctx);
29 void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx);
30 void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
31 void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
32
33 std::shared_ptr<ResourceManager> GetResourceManager();
34
35 Kernel::KEvent* joy_detach_event;
36 KernelHelpers::ServiceContext service_context;
37 std::shared_ptr<ResourceManager> resource_manager;
38};
39
40} // namespace Service::HID
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h
index a8fa19025..c8e6dab17 100644
--- a/src/core/hle/service/hid/irs.h
+++ b/src/core/hle/service/hid/irs.h
@@ -3,15 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/core.h"
6#include "core/hid/hid_types.h" 7#include "core/hid/hid_types.h"
7#include "core/hid/irs_types.h" 8#include "core/hid/irs_types.h"
8#include "core/hle/service/hid/irsensor/processor_base.h" 9#include "core/hle/service/hid/irsensor/processor_base.h"
9#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
10 11
11namespace Core {
12class System;
13}
14
15namespace Core::HID { 12namespace Core::HID {
16class EmulatedController; 13class EmulatedController;
17} // namespace Core::HID 14} // namespace Core::HID
diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp
new file mode 100644
index 000000000..d6f42c646
--- /dev/null
+++ b/src/core/hle/service/hid/resource_manager.cpp
@@ -0,0 +1,184 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/core_timing.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/kernel/k_shared_memory.h"
9#include "core/hle/service/hid/resource_manager.h"
10#include "core/hle/service/ipc_helpers.h"
11
12#include "core/hle/service/hid/controllers/console_sixaxis.h"
13#include "core/hle/service/hid/controllers/controller_base.h"
14#include "core/hle/service/hid/controllers/debug_pad.h"
15#include "core/hle/service/hid/controllers/gesture.h"
16#include "core/hle/service/hid/controllers/keyboard.h"
17#include "core/hle/service/hid/controllers/mouse.h"
18#include "core/hle/service/hid/controllers/npad.h"
19#include "core/hle/service/hid/controllers/palma.h"
20#include "core/hle/service/hid/controllers/stubbed.h"
21#include "core/hle/service/hid/controllers/touchscreen.h"
22#include "core/hle/service/hid/controllers/xpad.h"
23
24namespace Service::HID {
25
26// Updating period for each HID device.
27// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
28// Correct npad_update_ns is 4ms this is overclocked to lower input lag
29constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
30constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
31constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
32constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
33
34ResourceManager::ResourceManager(Core::System& system_)
35 : system{system_}, service_context{system_, "hid"} {}
36
37ResourceManager::~ResourceManager() = default;
38
39void ResourceManager::Initialize() {
40 if (is_initialized) {
41 return;
42 }
43
44 u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
45 MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
46 MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
47 MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
48 MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
49 MakeController<Controller_XPad>(HidController::XPad, shared_memory);
50 MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
51 MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
52 MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
53 MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
54 MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
55 MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
56 MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
57 MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
58 MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory);
59 MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
60
61 // Homebrew doesn't try to activate some controllers, so we activate them by default
62 GetController<Controller_NPad>(HidController::NPad).Activate();
63 GetController<Controller_Touchscreen>(HidController::Touchscreen).Activate();
64
65 GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
66 GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
67 GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
68 GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
69 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
70 GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00);
71
72 system.HIDCore().ReloadInputDevices();
73 is_initialized = true;
74}
75
76void ResourceManager::UpdateControllers(std::uintptr_t user_data,
77 std::chrono::nanoseconds ns_late) {
78 auto& core_timing = system.CoreTiming();
79
80 for (const auto& controller : controllers) {
81 // Keyboard has it's own update event
82 if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
83 continue;
84 }
85 // Mouse has it's own update event
86 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
87 continue;
88 }
89 // Npad has it's own update event
90 if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
91 continue;
92 }
93 controller->OnUpdate(core_timing);
94 }
95}
96
97void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
98 auto& core_timing = system.CoreTiming();
99
100 controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
101}
102
103void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data,
104 std::chrono::nanoseconds ns_late) {
105 auto& core_timing = system.CoreTiming();
106
107 controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
108 controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
109}
110
111void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
112 auto& core_timing = system.CoreTiming();
113
114 controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
115}
116
117IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource)
118 : ServiceFramework{system_, "IAppletResource"} {
119 static const FunctionInfo functions[] = {
120 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
121 };
122 RegisterHandlers(functions);
123
124 resource->Initialize();
125
126 // Register update callbacks
127 npad_update_event = Core::Timing::CreateEvent(
128 "HID::UpdatePadCallback",
129 [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
130 -> std::optional<std::chrono::nanoseconds> {
131 const auto guard = LockService();
132 resource->UpdateNpad(user_data, ns_late);
133 return std::nullopt;
134 });
135 default_update_event = Core::Timing::CreateEvent(
136 "HID::UpdateDefaultCallback",
137 [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
138 -> std::optional<std::chrono::nanoseconds> {
139 const auto guard = LockService();
140 resource->UpdateControllers(user_data, ns_late);
141 return std::nullopt;
142 });
143 mouse_keyboard_update_event = Core::Timing::CreateEvent(
144 "HID::UpdateMouseKeyboardCallback",
145 [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
146 -> std::optional<std::chrono::nanoseconds> {
147 const auto guard = LockService();
148 resource->UpdateMouseKeyboard(user_data, ns_late);
149 return std::nullopt;
150 });
151 motion_update_event = Core::Timing::CreateEvent(
152 "HID::UpdateMotionCallback",
153 [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
154 -> std::optional<std::chrono::nanoseconds> {
155 const auto guard = LockService();
156 resource->UpdateMotion(user_data, ns_late);
157 return std::nullopt;
158 });
159
160 system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
161 system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
162 default_update_event);
163 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
164 mouse_keyboard_update_event);
165 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
166 motion_update_event);
167}
168
169IAppletResource::~IAppletResource() {
170 system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
171 system.CoreTiming().UnscheduleEvent(default_update_event, 0);
172 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
173 system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
174}
175
176void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
177 LOG_DEBUG(Service_HID, "called");
178
179 IPC::ResponseBuilder rb{ctx, 2, 1};
180 rb.Push(ResultSuccess);
181 rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
182}
183
184} // namespace Service::HID
diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h
new file mode 100644
index 000000000..34dbf36bc
--- /dev/null
+++ b/src/core/hle/service/hid/resource_manager.h
@@ -0,0 +1,104 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <chrono>
7
8#include "core/core.h"
9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/service.h"
12
13namespace Core::Timing {
14struct EventType;
15}
16
17namespace Core::HID {
18class HIDCore;
19}
20
21namespace Service::HID {
22
23enum class HidController : std::size_t {
24 DebugPad,
25 Touchscreen,
26 Mouse,
27 Keyboard,
28 XPad,
29 HomeButton,
30 SleepButton,
31 CaptureButton,
32 InputDetector,
33 UniquePad,
34 NPad,
35 Gesture,
36 ConsoleSixAxisSensor,
37 DebugMouse,
38 Palma,
39
40 MaxControllers,
41};
42class ResourceManager {
43public:
44 explicit ResourceManager(Core::System& system_);
45 ~ResourceManager();
46
47 template <typename T>
48 T& GetController(HidController controller) {
49 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
50 }
51
52 template <typename T>
53 const T& GetController(HidController controller) const {
54 return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
55 }
56
57 void Initialize();
58
59 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
60 void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
61 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
62 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
63
64private:
65 template <typename T>
66 void MakeController(HidController controller, u8* shared_memory) {
67 if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
68 controllers[static_cast<std::size_t>(controller)] =
69 std::make_unique<T>(system, shared_memory);
70 } else {
71 controllers[static_cast<std::size_t>(controller)] =
72 std::make_unique<T>(system.HIDCore(), shared_memory);
73 }
74 }
75
76 template <typename T>
77 void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
78 controllers[static_cast<std::size_t>(controller)] =
79 std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
80 }
81
82 bool is_initialized{false};
83 std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
84 controllers{};
85
86 Core::System& system;
87 KernelHelpers::ServiceContext service_context;
88};
89
90class IAppletResource final : public ServiceFramework<IAppletResource> {
91public:
92 explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource);
93 ~IAppletResource() override;
94
95private:
96 void GetSharedMemoryHandle(HLERequestContext& ctx);
97
98 std::shared_ptr<Core::Timing::EventType> npad_update_event;
99 std::shared_ptr<Core::Timing::EventType> default_update_event;
100 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
101 std::shared_ptr<Core::Timing::EventType> motion_update_event;
102};
103
104} // namespace Service::HID
diff --git a/src/core/hle/service/nvnflinger/buffer_item.h b/src/core/hle/service/nvnflinger/buffer_item.h
index 3da8cc3aa..7fd808f54 100644
--- a/src/core/hle/service/nvnflinger/buffer_item.h
+++ b/src/core/hle/service/nvnflinger/buffer_item.h
@@ -15,7 +15,7 @@
15 15
16namespace Service::android { 16namespace Service::android {
17 17
18struct GraphicBuffer; 18class GraphicBuffer;
19 19
20class BufferItem final { 20class BufferItem final {
21public: 21public:
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
index 51291539d..d91886bed 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.cpp
@@ -5,7 +5,6 @@
5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp 5// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/service/nvdrv/core/nvmap.h"
9#include "core/hle/service/nvnflinger/buffer_item.h" 8#include "core/hle/service/nvnflinger/buffer_item.h"
10#include "core/hle/service/nvnflinger/buffer_queue_consumer.h" 9#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
11#include "core/hle/service/nvnflinger/buffer_queue_core.h" 10#include "core/hle/service/nvnflinger/buffer_queue_core.h"
@@ -14,9 +13,8 @@
14 13
15namespace Service::android { 14namespace Service::android {
16 15
17BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_, 16BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_)
18 Service::Nvidia::NvCore::NvMap& nvmap_) 17 : core{std::move(core_)}, slots{core->slots} {}
19 : core{std::move(core_)}, slots{core->slots}, nvmap(nvmap_) {}
20 18
21BufferQueueConsumer::~BufferQueueConsumer() = default; 19BufferQueueConsumer::~BufferQueueConsumer() = default;
22 20
@@ -136,8 +134,6 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
136 134
137 slots[slot].buffer_state = BufferState::Free; 135 slots[slot].buffer_state = BufferState::Free;
138 136
139 nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), true);
140
141 listener = core->connected_producer_listener; 137 listener = core->connected_producer_listener;
142 138
143 LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot); 139 LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot);
@@ -175,6 +171,25 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
175 return Status::NoError; 171 return Status::NoError;
176} 172}
177 173
174Status BufferQueueConsumer::Disconnect() {
175 LOG_DEBUG(Service_Nvnflinger, "called");
176
177 std::scoped_lock lock{core->mutex};
178
179 if (core->consumer_listener == nullptr) {
180 LOG_ERROR(Service_Nvnflinger, "no consumer is connected");
181 return Status::BadValue;
182 }
183
184 core->is_abandoned = true;
185 core->consumer_listener = nullptr;
186 core->queue.clear();
187 core->FreeAllBuffersLocked();
188 core->SignalDequeueCondition();
189
190 return Status::NoError;
191}
192
178Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) { 193Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
179 if (out_slot_mask == nullptr) { 194 if (out_slot_mask == nullptr) {
180 LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr"); 195 LOG_ERROR(Service_Nvnflinger, "out_slot_mask may not be nullptr");
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
index 50ed0bb5f..0a61e8dbd 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_consumer.h
@@ -13,10 +13,6 @@
13#include "core/hle/service/nvnflinger/buffer_queue_defs.h" 13#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
14#include "core/hle/service/nvnflinger/status.h" 14#include "core/hle/service/nvnflinger/status.h"
15 15
16namespace Service::Nvidia::NvCore {
17class NvMap;
18} // namespace Service::Nvidia::NvCore
19
20namespace Service::android { 16namespace Service::android {
21 17
22class BufferItem; 18class BufferItem;
@@ -25,19 +21,18 @@ class IConsumerListener;
25 21
26class BufferQueueConsumer final { 22class BufferQueueConsumer final {
27public: 23public:
28 explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_, 24 explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
29 Service::Nvidia::NvCore::NvMap& nvmap_);
30 ~BufferQueueConsumer(); 25 ~BufferQueueConsumer();
31 26
32 Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present); 27 Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
33 Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence); 28 Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
34 Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app); 29 Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
30 Status Disconnect();
35 Status GetReleasedBuffers(u64* out_slot_mask); 31 Status GetReleasedBuffers(u64* out_slot_mask);
36 32
37private: 33private:
38 std::shared_ptr<BufferQueueCore> core; 34 std::shared_ptr<BufferQueueCore> core;
39 BufferQueueDefs::SlotsType& slots; 35 BufferQueueDefs::SlotsType& slots;
40 Service::Nvidia::NvCore::NvMap& nvmap;
41}; 36};
42 37
43} // namespace Service::android 38} // namespace Service::android
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp
index ed66f6f5b..4ed5e5978 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp
@@ -14,24 +14,12 @@ BufferQueueCore::BufferQueueCore() = default;
14 14
15BufferQueueCore::~BufferQueueCore() = default; 15BufferQueueCore::~BufferQueueCore() = default;
16 16
17void BufferQueueCore::NotifyShutdown() {
18 std::scoped_lock lock{mutex};
19
20 is_shutting_down = true;
21
22 SignalDequeueCondition();
23}
24
25void BufferQueueCore::SignalDequeueCondition() { 17void BufferQueueCore::SignalDequeueCondition() {
26 dequeue_possible.store(true); 18 dequeue_possible.store(true);
27 dequeue_condition.notify_all(); 19 dequeue_condition.notify_all();
28} 20}
29 21
30bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) { 22bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {
31 if (is_shutting_down) {
32 return false;
33 }
34
35 dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); 23 dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); });
36 dequeue_possible.store(false); 24 dequeue_possible.store(false);
37 25
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_core.h b/src/core/hle/service/nvnflinger/buffer_queue_core.h
index 9164f08a0..e513d183b 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_core.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_core.h
@@ -34,8 +34,6 @@ public:
34 BufferQueueCore(); 34 BufferQueueCore();
35 ~BufferQueueCore(); 35 ~BufferQueueCore();
36 36
37 void NotifyShutdown();
38
39private: 37private:
40 void SignalDequeueCondition(); 38 void SignalDequeueCondition();
41 bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk); 39 bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
@@ -74,7 +72,6 @@ private:
74 u32 transform_hint{}; 72 u32 transform_hint{};
75 bool is_allocating{}; 73 bool is_allocating{};
76 mutable std::condition_variable_any is_allocating_condition; 74 mutable std::condition_variable_any is_allocating_condition;
77 bool is_shutting_down{};
78}; 75};
79 76
80} // namespace Service::android 77} // namespace Service::android
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index 6e7a49658..5d8762d25 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -13,7 +13,6 @@
13#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
14#include "core/hle/service/hle_ipc.h" 14#include "core/hle/service/hle_ipc.h"
15#include "core/hle/service/kernel_helpers.h" 15#include "core/hle/service/kernel_helpers.h"
16#include "core/hle/service/nvdrv/core/nvmap.h"
17#include "core/hle/service/nvnflinger/buffer_queue_core.h" 16#include "core/hle/service/nvnflinger/buffer_queue_core.h"
18#include "core/hle/service/nvnflinger/buffer_queue_producer.h" 17#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
19#include "core/hle/service/nvnflinger/consumer_listener.h" 18#include "core/hle/service/nvnflinger/consumer_listener.h"
@@ -533,8 +532,6 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
533 item.is_droppable = core->dequeue_buffer_cannot_block || async; 532 item.is_droppable = core->dequeue_buffer_cannot_block || async;
534 item.swap_interval = swap_interval; 533 item.swap_interval = swap_interval;
535 534
536 nvmap.DuplicateHandle(item.graphic_buffer->BufferId(), true);
537
538 sticky_transform = sticky_transform_; 535 sticky_transform = sticky_transform_;
539 536
540 if (core->queue.empty()) { 537 if (core->queue.empty()) {
@@ -744,19 +741,13 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
744 return Status::NoError; 741 return Status::NoError;
745 } 742 }
746 743
747 // HACK: We are not Android. Remove handle for items in queue, and clear queue.
748 // Allows synchronous destruction of nvmap handles.
749 for (auto& item : core->queue) {
750 nvmap.FreeHandle(item.graphic_buffer->BufferId(), true);
751 }
752 core->queue.clear();
753
754 switch (api) { 744 switch (api) {
755 case NativeWindowApi::Egl: 745 case NativeWindowApi::Egl:
756 case NativeWindowApi::Cpu: 746 case NativeWindowApi::Cpu:
757 case NativeWindowApi::Media: 747 case NativeWindowApi::Media:
758 case NativeWindowApi::Camera: 748 case NativeWindowApi::Camera:
759 if (core->connected_api == api) { 749 if (core->connected_api == api) {
750 core->queue.clear();
760 core->FreeAllBuffersLocked(); 751 core->FreeAllBuffersLocked();
761 core->connected_producer_listener = nullptr; 752 core->connected_producer_listener = nullptr;
762 core->connected_api = NativeWindowApi::NoConnectedApi; 753 core->connected_api = NativeWindowApi::NoConnectedApi;
@@ -785,7 +776,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
785} 776}
786 777
787Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot, 778Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
788 const std::shared_ptr<GraphicBuffer>& buffer) { 779 const std::shared_ptr<NvGraphicBuffer>& buffer) {
789 LOG_DEBUG(Service_Nvnflinger, "slot {}", slot); 780 LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
790 781
791 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { 782 if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
@@ -796,7 +787,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
796 787
797 slots[slot] = {}; 788 slots[slot] = {};
798 slots[slot].fence = Fence::NoFence(); 789 slots[slot].fence = Fence::NoFence();
799 slots[slot].graphic_buffer = buffer; 790 slots[slot].graphic_buffer = std::make_shared<GraphicBuffer>(nvmap, buffer);
800 slots[slot].frame_number = 0; 791 slots[slot].frame_number = 0;
801 792
802 // Most games preallocate a buffer and pass a valid buffer here. However, it is possible for 793 // Most games preallocate a buffer and pass a valid buffer here. However, it is possible for
@@ -839,7 +830,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
839 } 830 }
840 case TransactionId::SetPreallocatedBuffer: { 831 case TransactionId::SetPreallocatedBuffer: {
841 const auto slot = parcel_in.Read<s32>(); 832 const auto slot = parcel_in.Read<s32>();
842 const auto buffer = parcel_in.ReadObject<GraphicBuffer>(); 833 const auto buffer = parcel_in.ReadObject<NvGraphicBuffer>();
843 834
844 status = SetPreallocatedBuffer(slot, buffer); 835 status = SetPreallocatedBuffer(slot, buffer);
845 break; 836 break;
@@ -867,7 +858,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
867 858
868 status = RequestBuffer(slot, &buf); 859 status = RequestBuffer(slot, &buf);
869 860
870 parcel_out.WriteFlattenedObject(buf); 861 parcel_out.WriteFlattenedObject<NvGraphicBuffer>(buf.get());
871 break; 862 break;
872 } 863 }
873 case TransactionId::QueueBuffer: { 864 case TransactionId::QueueBuffer: {
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
index d4201c104..64c17d56c 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
@@ -38,6 +38,7 @@ namespace Service::android {
38 38
39class BufferQueueCore; 39class BufferQueueCore;
40class IProducerListener; 40class IProducerListener;
41struct NvGraphicBuffer;
41 42
42class BufferQueueProducer final : public IBinder { 43class BufferQueueProducer final : public IBinder {
43public: 44public:
@@ -65,7 +66,7 @@ public:
65 bool producer_controlled_by_app, QueueBufferOutput* output); 66 bool producer_controlled_by_app, QueueBufferOutput* output);
66 67
67 Status Disconnect(NativeWindowApi api); 68 Status Disconnect(NativeWindowApi api);
68 Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<GraphicBuffer>& buffer); 69 Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<NvGraphicBuffer>& buffer);
69 70
70private: 71private:
71 BufferQueueProducer(const BufferQueueProducer&) = delete; 72 BufferQueueProducer(const BufferQueueProducer&) = delete;
diff --git a/src/core/hle/service/nvnflinger/buffer_slot.h b/src/core/hle/service/nvnflinger/buffer_slot.h
index d8c9dec3b..d25bca049 100644
--- a/src/core/hle/service/nvnflinger/buffer_slot.h
+++ b/src/core/hle/service/nvnflinger/buffer_slot.h
@@ -13,7 +13,7 @@
13 13
14namespace Service::android { 14namespace Service::android {
15 15
16struct GraphicBuffer; 16class GraphicBuffer;
17 17
18enum class BufferState : u32 { 18enum class BufferState : u32 {
19 Free = 0, 19 Free = 0,
diff --git a/src/core/hle/service/nvnflinger/consumer_base.cpp b/src/core/hle/service/nvnflinger/consumer_base.cpp
index 4dcda8dac..1059e72bf 100644
--- a/src/core/hle/service/nvnflinger/consumer_base.cpp
+++ b/src/core/hle/service/nvnflinger/consumer_base.cpp
@@ -27,6 +27,26 @@ void ConsumerBase::Connect(bool controlled_by_app) {
27 consumer->Connect(shared_from_this(), controlled_by_app); 27 consumer->Connect(shared_from_this(), controlled_by_app);
28} 28}
29 29
30void ConsumerBase::Abandon() {
31 LOG_DEBUG(Service_Nvnflinger, "called");
32
33 std::scoped_lock lock{mutex};
34
35 if (!is_abandoned) {
36 this->AbandonLocked();
37 is_abandoned = true;
38 }
39}
40
41void ConsumerBase::AbandonLocked() {
42 for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
43 this->FreeBufferLocked(i);
44 }
45 // disconnect from the BufferQueue
46 consumer->Disconnect();
47 consumer = nullptr;
48}
49
30void ConsumerBase::FreeBufferLocked(s32 slot_index) { 50void ConsumerBase::FreeBufferLocked(s32 slot_index) {
31 LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index); 51 LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index);
32 52
diff --git a/src/core/hle/service/nvnflinger/consumer_base.h b/src/core/hle/service/nvnflinger/consumer_base.h
index 264829414..ea3e9e97a 100644
--- a/src/core/hle/service/nvnflinger/consumer_base.h
+++ b/src/core/hle/service/nvnflinger/consumer_base.h
@@ -24,6 +24,7 @@ class BufferQueueConsumer;
24class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> { 24class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> {
25public: 25public:
26 void Connect(bool controlled_by_app); 26 void Connect(bool controlled_by_app);
27 void Abandon();
27 28
28protected: 29protected:
29 explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); 30 explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
@@ -34,6 +35,7 @@ protected:
34 void OnBuffersReleased() override; 35 void OnBuffersReleased() override;
35 void OnSidebandStreamChanged() override; 36 void OnSidebandStreamChanged() override;
36 37
38 void AbandonLocked();
37 void FreeBufferLocked(s32 slot_index); 39 void FreeBufferLocked(s32 slot_index);
38 Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when); 40 Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when);
39 Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer); 41 Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer);
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
index 6dc327b8b..d7db24f42 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -166,7 +166,7 @@ constexpr SharedMemoryPoolLayout SharedBufferPoolLayout = [] {
166}(); 166}();
167 167
168void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) { 168void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
169 auto buffer = std::make_shared<android::GraphicBuffer>(); 169 auto buffer = std::make_shared<android::NvGraphicBuffer>();
170 buffer->width = SharedBufferWidth; 170 buffer->width = SharedBufferWidth;
171 buffer->height = SharedBufferHeight; 171 buffer->height = SharedBufferHeight;
172 buffer->stride = SharedBufferBlockLinearStride; 172 buffer->stride = SharedBufferBlockLinearStride;
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index bebb45eae..0745434c5 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -47,7 +47,10 @@ void Nvnflinger::SplitVSync(std::stop_token stop_token) {
47 vsync_signal.Wait(); 47 vsync_signal.Wait();
48 48
49 const auto lock_guard = Lock(); 49 const auto lock_guard = Lock();
50 Compose(); 50
51 if (!is_abandoned) {
52 Compose();
53 }
51 } 54 }
52} 55}
53 56
@@ -98,7 +101,6 @@ Nvnflinger::~Nvnflinger() {
98 } 101 }
99 102
100 ShutdownLayers(); 103 ShutdownLayers();
101 vsync_thread = {};
102 104
103 if (nvdrv) { 105 if (nvdrv) {
104 nvdrv->Close(disp_fd); 106 nvdrv->Close(disp_fd);
@@ -106,12 +108,20 @@ Nvnflinger::~Nvnflinger() {
106} 108}
107 109
108void Nvnflinger::ShutdownLayers() { 110void Nvnflinger::ShutdownLayers() {
109 const auto lock_guard = Lock(); 111 // Abandon consumers.
110 for (auto& display : displays) { 112 {
111 for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { 113 const auto lock_guard = Lock();
112 display.GetLayer(layer).Core().NotifyShutdown(); 114 for (auto& display : displays) {
115 for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
116 display.GetLayer(layer).GetConsumer().Abandon();
117 }
113 } 118 }
119
120 is_abandoned = true;
114 } 121 }
122
123 // Join the vsync thread, if it exists.
124 vsync_thread = {};
115} 125}
116 126
117void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { 127void Nvnflinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index 959d8b46b..f5d73acdb 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -140,6 +140,8 @@ private:
140 140
141 s32 swap_interval = 1; 141 s32 swap_interval = 1;
142 142
143 bool is_abandoned = false;
144
143 /// Event that handles screen composition. 145 /// Event that handles screen composition.
144 std::shared_ptr<Core::Timing::EventType> multi_composition_event; 146 std::shared_ptr<Core::Timing::EventType> multi_composition_event;
145 std::shared_ptr<Core::Timing::EventType> single_composition_event; 147 std::shared_ptr<Core::Timing::EventType> single_composition_event;
diff --git a/src/core/hle/service/nvnflinger/status.h b/src/core/hle/service/nvnflinger/status.h
index 7af166c40..3fa0fe15b 100644
--- a/src/core/hle/service/nvnflinger/status.h
+++ b/src/core/hle/service/nvnflinger/status.h
@@ -19,7 +19,7 @@ enum class Status : s32 {
19 Busy = -16, 19 Busy = -16,
20 NoInit = -19, 20 NoInit = -19,
21 BadValue = -22, 21 BadValue = -22,
22 InvalidOperation = -37, 22 InvalidOperation = -38,
23 BufferNeedsReallocation = 1, 23 BufferNeedsReallocation = 1,
24 ReleaseAllBuffers = 2, 24 ReleaseAllBuffers = 2,
25}; 25};
diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
new file mode 100644
index 000000000..ce70946ec
--- /dev/null
+++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.cpp
@@ -0,0 +1,34 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/nvdrv/core/nvmap.h"
5#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
6
7namespace Service::android {
8
9static NvGraphicBuffer GetBuffer(std::shared_ptr<NvGraphicBuffer>& buffer) {
10 if (buffer) {
11 return *buffer;
12 } else {
13 return {};
14 }
15}
16
17GraphicBuffer::GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
18 : NvGraphicBuffer(width_, height_, format_, usage_), m_nvmap(nullptr) {}
19
20GraphicBuffer::GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
21 std::shared_ptr<NvGraphicBuffer> buffer)
22 : NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) {
23 if (this->BufferId() > 0) {
24 m_nvmap->DuplicateHandle(this->BufferId(), true);
25 }
26}
27
28GraphicBuffer::~GraphicBuffer() {
29 if (m_nvmap != nullptr && this->BufferId() > 0) {
30 m_nvmap->FreeHandle(this->BufferId(), true);
31 }
32}
33
34} // namespace Service::android
diff --git a/src/core/hle/service/nvnflinger/ui/graphic_buffer.h b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h
index 3eac5cedd..da430aa75 100644
--- a/src/core/hle/service/nvnflinger/ui/graphic_buffer.h
+++ b/src/core/hle/service/nvnflinger/ui/graphic_buffer.h
@@ -6,16 +6,22 @@
6 6
7#pragma once 7#pragma once
8 8
9#include <memory>
10
9#include "common/common_funcs.h" 11#include "common/common_funcs.h"
10#include "common/common_types.h" 12#include "common/common_types.h"
11#include "core/hle/service/nvnflinger/pixel_format.h" 13#include "core/hle/service/nvnflinger/pixel_format.h"
12 14
15namespace Service::Nvidia::NvCore {
16class NvMap;
17} // namespace Service::Nvidia::NvCore
18
13namespace Service::android { 19namespace Service::android {
14 20
15struct GraphicBuffer final { 21struct NvGraphicBuffer {
16 constexpr GraphicBuffer() = default; 22 constexpr NvGraphicBuffer() = default;
17 23
18 constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_) 24 constexpr NvGraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
19 : width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_}, 25 : width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_},
20 usage{static_cast<s32>(usage_)} {} 26 usage{static_cast<s32>(usage_)} {}
21 27
@@ -93,6 +99,17 @@ struct GraphicBuffer final {
93 u32 offset{}; 99 u32 offset{};
94 INSERT_PADDING_WORDS(60); 100 INSERT_PADDING_WORDS(60);
95}; 101};
96static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size"); 102static_assert(sizeof(NvGraphicBuffer) == 0x16C, "NvGraphicBuffer has wrong size");
103
104class GraphicBuffer final : public NvGraphicBuffer {
105public:
106 explicit GraphicBuffer(u32 width, u32 height, PixelFormat format, u32 usage);
107 explicit GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
108 std::shared_ptr<NvGraphicBuffer> buffer);
109 ~GraphicBuffer();
110
111private:
112 Service::Nvidia::NvCore::NvMap* m_nvmap{};
113};
97 114
98} // namespace Service::android 115} // namespace Service::android
diff --git a/src/core/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp
index f0b5eff8a..d30f49877 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -35,7 +35,7 @@ static BufferQueue CreateBufferQueue(KernelHelpers::ServiceContext& service_cont
35 return { 35 return {
36 buffer_queue_core, 36 buffer_queue_core,
37 std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap), 37 std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap),
38 std::make_unique<android::BufferQueueConsumer>(buffer_queue_core, nvmap)}; 38 std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
39} 39}
40 40
41Display::Display(u64 id, std::string name_, 41Display::Display(u64 id, std::string name_,
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 84b60a928..a3431772a 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -1,8 +1,10 @@
1// SPDX-FileCopyrightText: 2015 Citra Emulator Project 1// SPDX-FileCopyrightText: 2015 Citra Emulator Project
2// SPDX-FileCopyrightText: 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 3// SPDX-License-Identifier: GPL-2.0-or-later
3 4
4#include <algorithm> 5#include <algorithm>
5#include <cstring> 6#include <cstring>
7#include <mutex>
6#include <span> 8#include <span>
7 9
8#include "common/assert.h" 10#include "common/assert.h"
@@ -10,6 +12,7 @@
10#include "common/common_types.h" 12#include "common/common_types.h"
11#include "common/logging/log.h" 13#include "common/logging/log.h"
12#include "common/page_table.h" 14#include "common/page_table.h"
15#include "common/scope_exit.h"
13#include "common/settings.h" 16#include "common/settings.h"
14#include "common/swap.h" 17#include "common/swap.h"
15#include "core/core.h" 18#include "core/core.h"
@@ -318,7 +321,7 @@ struct Memory::Impl {
318 [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount, 321 [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
319 u8* const host_ptr) { 322 u8* const host_ptr) {
320 if constexpr (!UNSAFE) { 323 if constexpr (!UNSAFE) {
321 system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount); 324 HandleRasterizerWrite(GetInteger(current_vaddr), copy_amount);
322 } 325 }
323 std::memcpy(host_ptr, src_buffer, copy_amount); 326 std::memcpy(host_ptr, src_buffer, copy_amount);
324 }, 327 },
@@ -351,7 +354,7 @@ struct Memory::Impl {
351 }, 354 },
352 [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount, 355 [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
353 u8* const host_ptr) { 356 u8* const host_ptr) {
354 system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount); 357 HandleRasterizerWrite(GetInteger(current_vaddr), copy_amount);
355 std::memset(host_ptr, 0, copy_amount); 358 std::memset(host_ptr, 0, copy_amount);
356 }, 359 },
357 [](const std::size_t copy_amount) {}); 360 [](const std::size_t copy_amount) {});
@@ -420,7 +423,7 @@ struct Memory::Impl {
420 const std::size_t block_size) { 423 const std::size_t block_size) {
421 // dc cvac: Store to point of coherency 424 // dc cvac: Store to point of coherency
422 // CPU flush -> GPU invalidate 425 // CPU flush -> GPU invalidate
423 system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size); 426 HandleRasterizerWrite(GetInteger(current_vaddr), block_size);
424 }; 427 };
425 return PerformCacheOperation(dest_addr, size, on_rasterizer); 428 return PerformCacheOperation(dest_addr, size, on_rasterizer);
426 } 429 }
@@ -430,7 +433,7 @@ struct Memory::Impl {
430 const std::size_t block_size) { 433 const std::size_t block_size) {
431 // dc civac: Store to point of coherency, and invalidate from cache 434 // dc civac: Store to point of coherency, and invalidate from cache
432 // CPU flush -> GPU invalidate 435 // CPU flush -> GPU invalidate
433 system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size); 436 HandleRasterizerWrite(GetInteger(current_vaddr), block_size);
434 }; 437 };
435 return PerformCacheOperation(dest_addr, size, on_rasterizer); 438 return PerformCacheOperation(dest_addr, size, on_rasterizer);
436 } 439 }
@@ -767,7 +770,18 @@ struct Memory::Impl {
767 } 770 }
768 771
769 void HandleRasterizerWrite(VAddr address, size_t size) { 772 void HandleRasterizerWrite(VAddr address, size_t size) {
770 const size_t core = system.GetCurrentHostThreadID(); 773 constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1;
774 const size_t core = std::min(system.GetCurrentHostThreadID(),
775 sys_core); // any other calls threads go to syscore.
776 // Guard on sys_core;
777 if (core == sys_core) [[unlikely]] {
778 sys_core_guard.lock();
779 }
780 SCOPE_EXIT({
781 if (core == sys_core) [[unlikely]] {
782 sys_core_guard.unlock();
783 }
784 });
771 auto& current_area = rasterizer_write_areas[core]; 785 auto& current_area = rasterizer_write_areas[core];
772 VAddr subaddress = address >> YUZU_PAGEBITS; 786 VAddr subaddress = address >> YUZU_PAGEBITS;
773 bool do_collection = current_area.last_address == subaddress; 787 bool do_collection = current_area.last_address == subaddress;
@@ -799,6 +813,7 @@ struct Memory::Impl {
799 rasterizer_read_areas{}; 813 rasterizer_read_areas{};
800 std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{}; 814 std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
801 std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers; 815 std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
816 std::mutex sys_core_guard;
802}; 817};
803 818
804Memory::Memory(Core::System& system_) : system{system_} { 819Memory::Memory(Core::System& system_) : system{system_} {
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index 53a89cc8f..da140c01c 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -10,7 +10,8 @@
10#include "core/hle/kernel/k_page_table.h" 10#include "core/hle/kernel/k_page_table.h"
11#include "core/hle/kernel/k_process.h" 11#include "core/hle/kernel/k_process.h"
12#include "core/hle/service/hid/controllers/npad.h" 12#include "core/hle/service/hid/controllers/npad.h"
13#include "core/hle/service/hid/hid.h" 13#include "core/hle/service/hid/hid_server.h"
14#include "core/hle/service/hid/resource_manager.h"
14#include "core/hle/service/sm/sm.h" 15#include "core/hle/service/sm/sm.h"
15#include "core/memory.h" 16#include "core/memory.h"
16#include "core/memory/cheat_engine.h" 17#include "core/memory/cheat_engine.h"
@@ -54,13 +55,13 @@ void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size)
54} 55}
55 56
56u64 StandardVmCallbacks::HidKeysDown() { 57u64 StandardVmCallbacks::HidKeysDown() {
57 const auto hid = system.ServiceManager().GetService<Service::HID::Hid>("hid"); 58 const auto hid = system.ServiceManager().GetService<Service::HID::IHidServer>("hid");
58 if (hid == nullptr) { 59 if (hid == nullptr) {
59 LOG_WARNING(CheatEngine, "Attempted to read input state, but hid is not initialized!"); 60 LOG_WARNING(CheatEngine, "Attempted to read input state, but hid is not initialized!");
60 return 0; 61 return 0;
61 } 62 }
62 63
63 const auto applet_resource = hid->GetAppletResource(); 64 const auto applet_resource = hid->GetResourceManager();
64 if (applet_resource == nullptr) { 65 if (applet_resource == nullptr) {
65 LOG_WARNING(CheatEngine, 66 LOG_WARNING(CheatEngine,
66 "Attempted to read input state, but applet resource is not initialized!"); 67 "Attempted to read input state, but applet resource is not initialized!");
diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp
index 3ad34884d..1ff296af5 100644
--- a/src/input_common/drivers/gc_adapter.cpp
+++ b/src/input_common/drivers/gc_adapter.cpp
@@ -415,7 +415,7 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p
415 // This list is missing ZL/ZR since those are not considered buttons. 415 // This list is missing ZL/ZR since those are not considered buttons.
416 // We will add those afterwards 416 // We will add those afterwards
417 // This list also excludes any button that can't be really mapped 417 // This list also excludes any button that can't be really mapped
418 static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 12> 418 static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 14>
419 switch_to_gcadapter_button = { 419 switch_to_gcadapter_button = {
420 std::pair{Settings::NativeButton::A, PadButton::ButtonA}, 420 std::pair{Settings::NativeButton::A, PadButton::ButtonA},
421 {Settings::NativeButton::B, PadButton::ButtonB}, 421 {Settings::NativeButton::B, PadButton::ButtonB},
@@ -426,8 +426,10 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p
426 {Settings::NativeButton::DUp, PadButton::ButtonUp}, 426 {Settings::NativeButton::DUp, PadButton::ButtonUp},
427 {Settings::NativeButton::DRight, PadButton::ButtonRight}, 427 {Settings::NativeButton::DRight, PadButton::ButtonRight},
428 {Settings::NativeButton::DDown, PadButton::ButtonDown}, 428 {Settings::NativeButton::DDown, PadButton::ButtonDown},
429 {Settings::NativeButton::SL, PadButton::TriggerL}, 429 {Settings::NativeButton::SLLeft, PadButton::TriggerL},
430 {Settings::NativeButton::SR, PadButton::TriggerR}, 430 {Settings::NativeButton::SRLeft, PadButton::TriggerR},
431 {Settings::NativeButton::SLRight, PadButton::TriggerL},
432 {Settings::NativeButton::SRRight, PadButton::TriggerR},
431 {Settings::NativeButton::R, PadButton::TriggerZ}, 433 {Settings::NativeButton::R, PadButton::TriggerZ},
432 }; 434 };
433 if (!params.Has("port")) { 435 if (!params.Has("port")) {
diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp
index 0aca5a3a3..72d2951f3 100644
--- a/src/input_common/drivers/joycon.cpp
+++ b/src/input_common/drivers/joycon.cpp
@@ -680,8 +680,8 @@ ButtonMapping Joycons::GetButtonMappingForDevice(const Common::ParamPackage& par
680 Common::ParamPackage sr_button_params = button_params; 680 Common::ParamPackage sr_button_params = button_params;
681 sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSL)); 681 sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSL));
682 sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSR)); 682 sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSR));
683 mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params)); 683 mapping.insert_or_assign(Settings::NativeButton::SLLeft, std::move(sl_button_params));
684 mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params)); 684 mapping.insert_or_assign(Settings::NativeButton::SRLeft, std::move(sr_button_params));
685 } 685 }
686 686
687 // Map SL and SR buttons for right joycons 687 // Map SL and SR buttons for right joycons
@@ -693,8 +693,8 @@ ButtonMapping Joycons::GetButtonMappingForDevice(const Common::ParamPackage& par
693 Common::ParamPackage sr_button_params = button_params; 693 Common::ParamPackage sr_button_params = button_params;
694 sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSL)); 694 sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSL));
695 sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSR)); 695 sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSR));
696 mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params)); 696 mapping.insert_or_assign(Settings::NativeButton::SLRight, std::move(sl_button_params));
697 mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params)); 697 mapping.insert_or_assign(Settings::NativeButton::SRRight, std::move(sr_button_params));
698 } 698 }
699 699
700 return mapping; 700 return mapping;
diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp
index 66e3ae9af..78f458afe 100644
--- a/src/input_common/drivers/sdl_driver.cpp
+++ b/src/input_common/drivers/sdl_driver.cpp
@@ -828,16 +828,18 @@ ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& p
828ButtonBindings SDLDriver::GetDefaultButtonBinding( 828ButtonBindings SDLDriver::GetDefaultButtonBinding(
829 const std::shared_ptr<SDLJoystick>& joystick) const { 829 const std::shared_ptr<SDLJoystick>& joystick) const {
830 // Default SL/SR mapping for other controllers 830 // Default SL/SR mapping for other controllers
831 auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; 831 auto sll_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
832 auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; 832 auto srl_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
833 auto slr_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
834 auto srr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
833 835
834 if (joystick->IsJoyconLeft()) { 836 if (joystick->IsJoyconLeft()) {
835 sl_button = SDL_CONTROLLER_BUTTON_PADDLE2; 837 sll_button = SDL_CONTROLLER_BUTTON_PADDLE2;
836 sr_button = SDL_CONTROLLER_BUTTON_PADDLE4; 838 srl_button = SDL_CONTROLLER_BUTTON_PADDLE4;
837 } 839 }
838 if (joystick->IsJoyconRight()) { 840 if (joystick->IsJoyconRight()) {
839 sl_button = SDL_CONTROLLER_BUTTON_PADDLE3; 841 slr_button = SDL_CONTROLLER_BUTTON_PADDLE3;
840 sr_button = SDL_CONTROLLER_BUTTON_PADDLE1; 842 srr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
841 } 843 }
842 844
843 return { 845 return {
@@ -855,8 +857,10 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding(
855 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, 857 {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
856 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, 858 {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
857 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, 859 {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
858 {Settings::NativeButton::SL, sl_button}, 860 {Settings::NativeButton::SLLeft, sll_button},
859 {Settings::NativeButton::SR, sr_button}, 861 {Settings::NativeButton::SRLeft, srl_button},
862 {Settings::NativeButton::SLRight, slr_button},
863 {Settings::NativeButton::SRRight, srr_button},
860 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, 864 {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
861 {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1}, 865 {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
862 }; 866 };
diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h
index fcba4e3c6..08e49a0da 100644
--- a/src/input_common/drivers/sdl_driver.h
+++ b/src/input_common/drivers/sdl_driver.h
@@ -24,7 +24,7 @@ namespace InputCommon {
24class SDLJoystick; 24class SDLJoystick;
25 25
26using ButtonBindings = 26using ButtonBindings =
27 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 18>; 27 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 20>;
28using ZButtonBindings = 28using ZButtonBindings =
29 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>; 29 std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
30 30
diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp
index 77db60e92..60821b31a 100644
--- a/src/input_common/drivers/udp_client.cpp
+++ b/src/input_common/drivers/udp_client.cpp
@@ -396,7 +396,7 @@ std::vector<Common::ParamPackage> UDPClient::GetInputDevices() const {
396 396
397ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) { 397ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) {
398 // This list excludes any button that can't be really mapped 398 // This list excludes any button that can't be really mapped
399 static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 20> 399 static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 22>
400 switch_to_dsu_button = { 400 switch_to_dsu_button = {
401 std::pair{Settings::NativeButton::A, PadButton::Circle}, 401 std::pair{Settings::NativeButton::A, PadButton::Circle},
402 {Settings::NativeButton::B, PadButton::Cross}, 402 {Settings::NativeButton::B, PadButton::Cross},
@@ -412,8 +412,10 @@ ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& p
412 {Settings::NativeButton::R, PadButton::R1}, 412 {Settings::NativeButton::R, PadButton::R1},
413 {Settings::NativeButton::ZL, PadButton::L2}, 413 {Settings::NativeButton::ZL, PadButton::L2},
414 {Settings::NativeButton::ZR, PadButton::R2}, 414 {Settings::NativeButton::ZR, PadButton::R2},
415 {Settings::NativeButton::SL, PadButton::L2}, 415 {Settings::NativeButton::SLLeft, PadButton::L2},
416 {Settings::NativeButton::SR, PadButton::R2}, 416 {Settings::NativeButton::SRLeft, PadButton::R2},
417 {Settings::NativeButton::SLRight, PadButton::L2},
418 {Settings::NativeButton::SRRight, PadButton::R2},
417 {Settings::NativeButton::LStick, PadButton::L3}, 419 {Settings::NativeButton::LStick, PadButton::L3},
418 {Settings::NativeButton::RStick, PadButton::R3}, 420 {Settings::NativeButton::RStick, PadButton::R3},
419 {Settings::NativeButton::Home, PadButton::Home}, 421 {Settings::NativeButton::Home, PadButton::Home},
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt
index 83b763447..19db17c6d 100644
--- a/src/shader_recompiler/CMakeLists.txt
+++ b/src/shader_recompiler/CMakeLists.txt
@@ -231,6 +231,7 @@ add_library(shader_recompiler STATIC
231 ir_opt/rescaling_pass.cpp 231 ir_opt/rescaling_pass.cpp
232 ir_opt/ssa_rewrite_pass.cpp 232 ir_opt/ssa_rewrite_pass.cpp
233 ir_opt/texture_pass.cpp 233 ir_opt/texture_pass.cpp
234 ir_opt/vendor_workaround_pass.cpp
234 ir_opt/verification_pass.cpp 235 ir_opt/verification_pass.cpp
235 object_pool.h 236 object_pool.h
236 precompiled_headers.h 237 precompiled_headers.h
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
index d0e308124..64e7bad75 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm_image.cpp
@@ -559,12 +559,12 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
559 const IR::Value& offset, const IR::Value& lod_clamp) { 559 const IR::Value& offset, const IR::Value& lod_clamp) {
560 const auto info{inst.Flags<IR::TextureInstInfo>()}; 560 const auto info{inst.Flags<IR::TextureInstInfo>()};
561 ScopedRegister dpdx, dpdy, coords; 561 ScopedRegister dpdx, dpdy, coords;
562 const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp}; 562 const bool multi_component{info.num_derivatives > 1 || info.has_lod_clamp};
563 if (multi_component) { 563 if (multi_component) {
564 // Allocate this early to avoid aliasing other registers 564 // Allocate this early to avoid aliasing other registers
565 dpdx = ScopedRegister{ctx.reg_alloc}; 565 dpdx = ScopedRegister{ctx.reg_alloc};
566 dpdy = ScopedRegister{ctx.reg_alloc}; 566 dpdy = ScopedRegister{ctx.reg_alloc};
567 if (info.num_derivates >= 3) { 567 if (info.num_derivatives >= 3) {
568 coords = ScopedRegister{ctx.reg_alloc}; 568 coords = ScopedRegister{ctx.reg_alloc};
569 } 569 }
570 } 570 }
@@ -584,7 +584,7 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
584 dpdx.reg, derivatives_vec, dpdx.reg, derivatives_vec, dpdy.reg, derivatives_vec, 584 dpdx.reg, derivatives_vec, dpdx.reg, derivatives_vec, dpdy.reg, derivatives_vec,
585 dpdy.reg, derivatives_vec); 585 dpdy.reg, derivatives_vec);
586 Register final_coord; 586 Register final_coord;
587 if (info.num_derivates >= 3) { 587 if (info.num_derivatives >= 3) {
588 ctx.Add("MOV.F {}.z,{}.x;" 588 ctx.Add("MOV.F {}.z,{}.x;"
589 "MOV.F {}.z,{}.y;", 589 "MOV.F {}.z,{}.y;",
590 dpdx.reg, coord_vec, dpdy.reg, coord_vec); 590 dpdx.reg, coord_vec, dpdy.reg, coord_vec);
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
index d9872ecc2..6e940bd5a 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
@@ -548,15 +548,15 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
548 if (sparse_inst) { 548 if (sparse_inst) {
549 throw NotImplementedException("EmitImageGradient Sparse"); 549 throw NotImplementedException("EmitImageGradient Sparse");
550 } 550 }
551 if (!offset.IsEmpty() && info.num_derivates <= 2) { 551 if (!offset.IsEmpty() && info.num_derivatives <= 2) {
552 throw NotImplementedException("EmitImageGradient offset"); 552 throw NotImplementedException("EmitImageGradient offset");
553 } 553 }
554 const auto texture{Texture(ctx, info, index)}; 554 const auto texture{Texture(ctx, info, index)};
555 const auto texel{ctx.var_alloc.Define(inst, GlslVarType::F32x4)}; 555 const auto texel{ctx.var_alloc.Define(inst, GlslVarType::F32x4)};
556 const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp}; 556 const bool multi_component{info.num_derivatives > 1 || info.has_lod_clamp};
557 const auto derivatives_vec{ctx.var_alloc.Consume(derivatives)}; 557 const auto derivatives_vec{ctx.var_alloc.Consume(derivatives)};
558 if (multi_component) { 558 if (multi_component) {
559 if (info.num_derivates >= 3) { 559 if (info.num_derivatives >= 3) {
560 const auto offset_vec{ctx.var_alloc.Consume(offset)}; 560 const auto offset_vec{ctx.var_alloc.Consume(offset)};
561 ctx.Add("{}=textureGrad({},{},vec3({}.xz, {}.x),vec3({}.yw, {}.y));", texel, texture, 561 ctx.Add("{}=textureGrad({},{},vec3({}.xz, {}.x),vec3({}.yw, {}.y));", texel, texture,
562 coords, derivatives_vec, offset_vec, derivatives_vec, offset_vec); 562 coords, derivatives_vec, offset_vec, derivatives_vec, offset_vec);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
index 8decdf399..22ceca19c 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
@@ -67,22 +67,22 @@ public:
67 } 67 }
68 } 68 }
69 69
70 explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates, u32 num_derivates, 70 explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives,
71 Id offset, Id lod_clamp) { 71 u32 num_derivatives, Id offset, Id lod_clamp) {
72 if (!Sirit::ValidId(derivates)) { 72 if (!Sirit::ValidId(derivatives)) {
73 throw LogicError("Derivates must be present"); 73 throw LogicError("Derivatives must be present");
74 } 74 }
75 boost::container::static_vector<Id, 3> deriv_x_accum; 75 boost::container::static_vector<Id, 3> deriv_x_accum;
76 boost::container::static_vector<Id, 3> deriv_y_accum; 76 boost::container::static_vector<Id, 3> deriv_y_accum;
77 for (u32 i = 0; i < num_derivates; ++i) { 77 for (u32 i = 0; i < num_derivatives; ++i) {
78 deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2)); 78 deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2));
79 deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2 + 1)); 79 deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2 + 1));
80 } 80 }
81 const Id derivates_X{ctx.OpCompositeConstruct( 81 const Id derivatives_X{ctx.OpCompositeConstruct(
82 ctx.F32[num_derivates], std::span{deriv_x_accum.data(), deriv_x_accum.size()})}; 82 ctx.F32[num_derivatives], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
83 const Id derivates_Y{ctx.OpCompositeConstruct( 83 const Id derivatives_Y{ctx.OpCompositeConstruct(
84 ctx.F32[num_derivates], std::span{deriv_y_accum.data(), deriv_y_accum.size()})}; 84 ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
85 Add(spv::ImageOperandsMask::Grad, derivates_X, derivates_Y); 85 Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y);
86 if (Sirit::ValidId(offset)) { 86 if (Sirit::ValidId(offset)) {
87 Add(spv::ImageOperandsMask::Offset, offset); 87 Add(spv::ImageOperandsMask::Offset, offset);
88 } 88 }
@@ -91,26 +91,26 @@ public:
91 } 91 }
92 } 92 }
93 93
94 explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates_1, Id derivates_2, 94 explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2,
95 Id offset, Id lod_clamp) { 95 Id offset, Id lod_clamp) {
96 if (!Sirit::ValidId(derivates_1) || !Sirit::ValidId(derivates_2)) { 96 if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) {
97 throw LogicError("Derivates must be present"); 97 throw LogicError("Derivatives must be present");
98 } 98 }
99 boost::container::static_vector<Id, 3> deriv_1_accum{ 99 boost::container::static_vector<Id, 3> deriv_1_accum{
100 ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 0), 100 ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 0),
101 ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 2), 101 ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 2),
102 ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 0), 102 ctx.OpCompositeExtract(ctx.F32[1], derivatives_2, 0),
103 }; 103 };
104 boost::container::static_vector<Id, 3> deriv_2_accum{ 104 boost::container::static_vector<Id, 3> deriv_2_accum{
105 ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 1), 105 ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 1),
106 ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 3), 106 ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 3),
107 ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 1), 107 ctx.OpCompositeExtract(ctx.F32[1], derivatives_2, 1),
108 }; 108 };
109 const Id derivates_id1{ctx.OpCompositeConstruct( 109 const Id derivatives_id1{ctx.OpCompositeConstruct(
110 ctx.F32[3], std::span{deriv_1_accum.data(), deriv_1_accum.size()})}; 110 ctx.F32[3], std::span{deriv_1_accum.data(), deriv_1_accum.size()})};
111 const Id derivates_id2{ctx.OpCompositeConstruct( 111 const Id derivatives_id2{ctx.OpCompositeConstruct(
112 ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})}; 112 ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})};
113 Add(spv::ImageOperandsMask::Grad, derivates_id1, derivates_id2); 113 Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2);
114 if (Sirit::ValidId(offset)) { 114 if (Sirit::ValidId(offset)) {
115 Add(spv::ImageOperandsMask::Offset, offset); 115 Add(spv::ImageOperandsMask::Offset, offset);
116 } 116 }
@@ -548,12 +548,12 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
548} 548}
549 549
550Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 550Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
551 Id derivates, Id offset, Id lod_clamp) { 551 Id derivatives, Id offset, Id lod_clamp) {
552 const auto info{inst->Flags<IR::TextureInstInfo>()}; 552 const auto info{inst->Flags<IR::TextureInstInfo>()};
553 const auto operands = 553 const auto operands =
554 info.num_derivates == 3 554 info.num_derivatives == 3
555 ? ImageOperands(ctx, info.has_lod_clamp != 0, derivates, offset, {}, lod_clamp) 555 ? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, offset, {}, lod_clamp)
556 : ImageOperands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, offset, 556 : ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives, offset,
557 lod_clamp); 557 lod_clamp);
558 return Emit(&EmitContext::OpImageSparseSampleExplicitLod, 558 return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
559 &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4], 559 &EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index a440b557d..7d34575c8 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -543,7 +543,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
543 const IR::Value& skip_mips); 543 const IR::Value& skip_mips);
544Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); 544Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
545Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, 545Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
546 Id derivates, Id offset, Id lod_clamp); 546 Id derivatives, Id offset, Id lod_clamp);
547Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords); 547Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
548void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color); 548void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
549Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index); 549Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index);
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.cpp b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
index b7caa4246..49171c470 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.cpp
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.cpp
@@ -1864,11 +1864,11 @@ Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, Texture
1864 return Inst(op, Flags{info}, handle, coords); 1864 return Inst(op, Flags{info}, handle, coords);
1865} 1865}
1866 1866
1867Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivates, 1867Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivatives,
1868 const Value& offset, const F32& lod_clamp, TextureInstInfo info) { 1868 const Value& offset, const F32& lod_clamp, TextureInstInfo info) {
1869 const Opcode op{handle.IsImmediate() ? Opcode::BoundImageGradient 1869 const Opcode op{handle.IsImmediate() ? Opcode::BoundImageGradient
1870 : Opcode::BindlessImageGradient}; 1870 : Opcode::BindlessImageGradient};
1871 return Inst(op, Flags{info}, handle, coords, derivates, offset, lod_clamp); 1871 return Inst(op, Flags{info}, handle, coords, derivatives, offset, lod_clamp);
1872} 1872}
1873 1873
1874Value IREmitter::ImageRead(const Value& handle, const Value& coords, TextureInstInfo info) { 1874Value IREmitter::ImageRead(const Value& handle, const Value& coords, TextureInstInfo info) {
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index f3c81dbe1..6c30897f4 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -335,7 +335,7 @@ public:
335 [[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset, 335 [[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
336 const U32& lod, const U32& multisampling, TextureInstInfo info); 336 const U32& lod, const U32& multisampling, TextureInstInfo info);
337 [[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords, 337 [[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
338 const Value& derivates, const Value& offset, 338 const Value& derivatives, const Value& offset,
339 const F32& lod_clamp, TextureInstInfo info); 339 const F32& lod_clamp, TextureInstInfo info);
340 [[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info); 340 [[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info);
341 void ImageWrite(const Value& handle, const Value& coords, const Value& color, 341 void ImageWrite(const Value& handle, const Value& coords, const Value& color,
diff --git a/src/shader_recompiler/frontend/ir/modifiers.h b/src/shader_recompiler/frontend/ir/modifiers.h
index 1e9e8c8f5..c20c2401f 100644
--- a/src/shader_recompiler/frontend/ir/modifiers.h
+++ b/src/shader_recompiler/frontend/ir/modifiers.h
@@ -40,7 +40,7 @@ union TextureInstInfo {
40 BitField<21, 1, u32> has_lod_clamp; 40 BitField<21, 1, u32> has_lod_clamp;
41 BitField<22, 1, u32> relaxed_precision; 41 BitField<22, 1, u32> relaxed_precision;
42 BitField<23, 2, u32> gather_component; 42 BitField<23, 2, u32> gather_component;
43 BitField<25, 2, u32> num_derivates; 43 BitField<25, 2, u32> num_derivatives;
44 BitField<27, 3, ImageFormat> image_format; 44 BitField<27, 3, ImageFormat> image_format;
45 BitField<30, 1, u32> ndv_is_active; 45 BitField<30, 1, u32> ndv_is_active;
46}; 46};
diff --git a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp
index dd34507bc..4ce3dd0cd 100644
--- a/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate/impl/texture_gradient.cpp
@@ -59,7 +59,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
59 BitField<51, 3, IR::Pred> sparse_pred; 59 BitField<51, 3, IR::Pred> sparse_pred;
60 BitField<0, 8, IR::Reg> dest_reg; 60 BitField<0, 8, IR::Reg> dest_reg;
61 BitField<8, 8, IR::Reg> coord_reg; 61 BitField<8, 8, IR::Reg> coord_reg;
62 BitField<20, 8, IR::Reg> derivate_reg; 62 BitField<20, 8, IR::Reg> derivative_reg;
63 BitField<28, 3, TextureType> type; 63 BitField<28, 3, TextureType> type;
64 BitField<31, 4, u64> mask; 64 BitField<31, 4, u64> mask;
65 BitField<36, 13, u64> cbuf_offset; 65 BitField<36, 13, u64> cbuf_offset;
@@ -71,7 +71,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
71 } 71 }
72 72
73 IR::Value coords; 73 IR::Value coords;
74 u32 num_derivates{}; 74 u32 num_derivatives{};
75 IR::Reg base_reg{txd.coord_reg}; 75 IR::Reg base_reg{txd.coord_reg};
76 IR::Reg last_reg; 76 IR::Reg last_reg;
77 IR::Value handle; 77 IR::Value handle;
@@ -90,42 +90,42 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
90 switch (txd.type) { 90 switch (txd.type) {
91 case TextureType::_1D: { 91 case TextureType::_1D: {
92 coords = v.F(base_reg); 92 coords = v.F(base_reg);
93 num_derivates = 1; 93 num_derivatives = 1;
94 last_reg = base_reg + 1; 94 last_reg = base_reg + 1;
95 break; 95 break;
96 } 96 }
97 case TextureType::ARRAY_1D: { 97 case TextureType::ARRAY_1D: {
98 last_reg = base_reg + 1; 98 last_reg = base_reg + 1;
99 coords = v.ir.CompositeConstruct(v.F(base_reg), read_array()); 99 coords = v.ir.CompositeConstruct(v.F(base_reg), read_array());
100 num_derivates = 1; 100 num_derivatives = 1;
101 break; 101 break;
102 } 102 }
103 case TextureType::_2D: { 103 case TextureType::_2D: {
104 last_reg = base_reg + 2; 104 last_reg = base_reg + 2;
105 coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1)); 105 coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1));
106 num_derivates = 2; 106 num_derivatives = 2;
107 break; 107 break;
108 } 108 }
109 case TextureType::ARRAY_2D: { 109 case TextureType::ARRAY_2D: {
110 last_reg = base_reg + 2; 110 last_reg = base_reg + 2;
111 coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1), read_array()); 111 coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1), read_array());
112 num_derivates = 2; 112 num_derivatives = 2;
113 break; 113 break;
114 } 114 }
115 default: 115 default:
116 throw NotImplementedException("Invalid texture type"); 116 throw NotImplementedException("Invalid texture type");
117 } 117 }
118 118
119 const IR::Reg derivate_reg{txd.derivate_reg}; 119 const IR::Reg derivative_reg{txd.derivative_reg};
120 IR::Value derivates; 120 IR::Value derivatives;
121 switch (num_derivates) { 121 switch (num_derivatives) {
122 case 1: { 122 case 1: {
123 derivates = v.ir.CompositeConstruct(v.F(derivate_reg), v.F(derivate_reg + 1)); 123 derivatives = v.ir.CompositeConstruct(v.F(derivative_reg), v.F(derivative_reg + 1));
124 break; 124 break;
125 } 125 }
126 case 2: { 126 case 2: {
127 derivates = v.ir.CompositeConstruct(v.F(derivate_reg), v.F(derivate_reg + 1), 127 derivatives = v.ir.CompositeConstruct(v.F(derivative_reg), v.F(derivative_reg + 1),
128 v.F(derivate_reg + 2), v.F(derivate_reg + 3)); 128 v.F(derivative_reg + 2), v.F(derivative_reg + 3));
129 break; 129 break;
130 } 130 }
131 default: 131 default:
@@ -150,9 +150,10 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
150 150
151 IR::TextureInstInfo info{}; 151 IR::TextureInstInfo info{};
152 info.type.Assign(GetType(txd.type)); 152 info.type.Assign(GetType(txd.type));
153 info.num_derivates.Assign(num_derivates); 153 info.num_derivatives.Assign(num_derivatives);
154 info.has_lod_clamp.Assign(has_lod_clamp ? 1 : 0); 154 info.has_lod_clamp.Assign(has_lod_clamp ? 1 : 0);
155 const IR::Value sample{v.ir.ImageGradient(handle, coords, derivates, offset, lod_clamp, info)}; 155 const IR::Value sample{
156 v.ir.ImageGradient(handle, coords, derivatives, offset, lod_clamp, info)};
156 157
157 IR::Reg dest_reg{txd.dest_reg}; 158 IR::Reg dest_reg{txd.dest_reg};
158 for (size_t element = 0; element < 4; ++element) { 159 for (size_t element = 0; element < 4; ++element) {
diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp
index 928b35561..8fac6bad3 100644
--- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp
+++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp
@@ -310,6 +310,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
310 } 310 }
311 Optimization::CollectShaderInfoPass(env, program); 311 Optimization::CollectShaderInfoPass(env, program);
312 Optimization::LayerPass(program, host_info); 312 Optimization::LayerPass(program, host_info);
313 Optimization::VendorWorkaroundPass(program);
313 314
314 CollectInterpolationInfo(env, program); 315 CollectInterpolationInfo(env, program);
315 AddNVNStorageBuffers(program); 316 AddNVNStorageBuffers(program);
diff --git a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
index f46e55122..ec12c843a 100644
--- a/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
+++ b/src/shader_recompiler/ir_opt/constant_propagation_pass.cpp
@@ -428,7 +428,7 @@ void FoldFPAdd32(IR::Inst& inst) {
428 } 428 }
429} 429}
430 430
431bool FoldDerivateYFromCorrection(IR::Inst& inst) { 431bool FoldDerivativeYFromCorrection(IR::Inst& inst) {
432 const IR::Value lhs_value{inst.Arg(0)}; 432 const IR::Value lhs_value{inst.Arg(0)};
433 const IR::Value rhs_value{inst.Arg(1)}; 433 const IR::Value rhs_value{inst.Arg(1)};
434 IR::Inst* const lhs_op{lhs_value.InstRecursive()}; 434 IR::Inst* const lhs_op{lhs_value.InstRecursive()};
@@ -464,7 +464,7 @@ void FoldFPMul32(IR::Inst& inst) {
464 if (lhs_value.IsImmediate() || rhs_value.IsImmediate()) { 464 if (lhs_value.IsImmediate() || rhs_value.IsImmediate()) {
465 return; 465 return;
466 } 466 }
467 if (FoldDerivateYFromCorrection(inst)) { 467 if (FoldDerivativeYFromCorrection(inst)) {
468 return; 468 return;
469 } 469 }
470 IR::Inst* const lhs_op{lhs_value.InstRecursive()}; 470 IR::Inst* const lhs_op{lhs_value.InstRecursive()};
@@ -699,7 +699,7 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
699 } 699 }
700} 700}
701 701
702bool FindGradient3DDerivates(std::array<IR::Value, 3>& results, IR::Value coord) { 702bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coord) {
703 if (coord.IsImmediate()) { 703 if (coord.IsImmediate()) {
704 return false; 704 return false;
705 } 705 }
@@ -834,7 +834,7 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
834 IR::Inst* const inst2 = coords.InstRecursive(); 834 IR::Inst* const inst2 = coords.InstRecursive();
835 std::array<std::array<IR::Value, 3>, 3> results_matrix; 835 std::array<std::array<IR::Value, 3>, 3> results_matrix;
836 for (size_t i = 0; i < 3; i++) { 836 for (size_t i = 0; i < 3; i++) {
837 if (!FindGradient3DDerivates(results_matrix[i], inst2->Arg(i).Resolve())) { 837 if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) {
838 return; 838 return;
839 } 839 }
840 } 840 }
@@ -852,7 +852,7 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
852 IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2], 852 IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2],
853 results_matrix[1][1], results_matrix[1][2]); 853 results_matrix[1][1], results_matrix[1][2]);
854 IR::Value derivatives_2 = ir.CompositeConstruct(results_matrix[2][1], results_matrix[2][2]); 854 IR::Value derivatives_2 = ir.CompositeConstruct(results_matrix[2][1], results_matrix[2][2]);
855 info.num_derivates.Assign(3); 855 info.num_derivatives.Assign(3);
856 IR::Value new_gradient_instruction = 856 IR::Value new_gradient_instruction =
857 ir.ImageGradient(handle, new_coords, derivatives_1, derivatives_2, lod_clamp, info); 857 ir.ImageGradient(handle, new_coords, derivatives_1, derivatives_2, lod_clamp, info);
858 IR::Inst* const new_inst = new_gradient_instruction.InstRecursive(); 858 IR::Inst* const new_inst = new_gradient_instruction.InstRecursive();
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h
index 629d18fa1..d4d5285e5 100644
--- a/src/shader_recompiler/ir_opt/passes.h
+++ b/src/shader_recompiler/ir_opt/passes.h
@@ -26,6 +26,7 @@ void SsaRewritePass(IR::Program& program);
26void PositionPass(Environment& env, IR::Program& program); 26void PositionPass(Environment& env, IR::Program& program);
27void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info); 27void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info);
28void LayerPass(IR::Program& program, const HostTranslateInfo& host_info); 28void LayerPass(IR::Program& program, const HostTranslateInfo& host_info);
29void VendorWorkaroundPass(IR::Program& program);
29void VerificationPass(const IR::Program& program); 30void VerificationPass(const IR::Program& program);
30 31
31// Dual Vertex 32// Dual Vertex
diff --git a/src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp b/src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp
new file mode 100644
index 000000000..08c658cb8
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/vendor_workaround_pass.cpp
@@ -0,0 +1,79 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "shader_recompiler/frontend/ir/basic_block.h"
5#include "shader_recompiler/frontend/ir/ir_emitter.h"
6#include "shader_recompiler/frontend/ir/value.h"
7#include "shader_recompiler/ir_opt/passes.h"
8
9namespace Shader::Optimization {
10
11namespace {
12void AddingByteSwapsWorkaround(IR::Block& block, IR::Inst& inst) {
13 /*
14 * Workaround for an NVIDIA bug seen in Super Mario RPG
15 *
16 * We are looking for this pattern:
17 * %lhs_bfe = BitFieldUExtract %factor_a, #0, #16
18 * %lhs_mul = IMul32 %lhs_bfe, %factor_b // potentially optional?
19 * %lhs_shl = ShiftLeftLogical32 %lhs_mul, #16
20 * %rhs_bfe = BitFieldUExtract %factor_a, #16, #16
21 * %result = IAdd32 %lhs_shl, %rhs_bfe
22 *
23 * And replacing the IAdd32 with a BitwiseOr32
24 * %result = BitwiseOr32 %lhs_shl, %rhs_bfe
25 *
26 */
27 IR::Inst* const lhs_shl{inst.Arg(0).TryInstRecursive()};
28 IR::Inst* const rhs_bfe{inst.Arg(1).TryInstRecursive()};
29 if (!lhs_shl || !rhs_bfe) {
30 return;
31 }
32 if (lhs_shl->GetOpcode() != IR::Opcode::ShiftLeftLogical32 ||
33 lhs_shl->Arg(1) != IR::Value{16U}) {
34 return;
35 }
36 if (rhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract || rhs_bfe->Arg(1) != IR::Value{16U} ||
37 rhs_bfe->Arg(2) != IR::Value{16U}) {
38 return;
39 }
40 IR::Inst* const lhs_mul{lhs_shl->Arg(0).TryInstRecursive()};
41 if (!lhs_mul) {
42 return;
43 }
44 const bool lhs_mul_optional{lhs_mul->GetOpcode() == IR::Opcode::BitFieldUExtract};
45 if (lhs_mul->GetOpcode() != IR::Opcode::IMul32 &&
46 lhs_mul->GetOpcode() != IR::Opcode::BitFieldUExtract) {
47 return;
48 }
49 IR::Inst* const lhs_bfe{lhs_mul_optional ? lhs_mul : lhs_mul->Arg(0).TryInstRecursive()};
50 if (!lhs_bfe) {
51 return;
52 }
53 if (lhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract) {
54 return;
55 }
56 if (lhs_bfe->Arg(1) != IR::Value{0U} || lhs_bfe->Arg(2) != IR::Value{16U}) {
57 return;
58 }
59 IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
60 inst.ReplaceUsesWith(ir.BitwiseOr(IR::U32{inst.Arg(0)}, IR::U32{inst.Arg(1)}));
61}
62
63} // Anonymous namespace
64
65void VendorWorkaroundPass(IR::Program& program) {
66 for (IR::Block* const block : program.post_order_blocks) {
67 for (IR::Inst& inst : block->Instructions()) {
68 switch (inst.GetOpcode()) {
69 case IR::Opcode::IAdd32:
70 AddingByteSwapsWorkaround(*block, inst);
71 break;
72 default:
73 break;
74 }
75 }
76 }
77}
78
79} // namespace Shader::Optimization
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 081a574e8..f5b10411b 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -1192,11 +1192,6 @@ void BufferCache<P>::UpdateDrawIndirect() {
1192 .size = static_cast<u32>(size), 1192 .size = static_cast<u32>(size),
1193 .buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)), 1193 .buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)),
1194 }; 1194 };
1195 VAddr cpu_addr_start = Common::AlignDown(*cpu_addr, 64);
1196 VAddr cpu_addr_end = Common::AlignUp(*cpu_addr + size, 64);
1197 IntervalType interval{cpu_addr_start, cpu_addr_end};
1198 ClearDownload(interval);
1199 common_ranges.subtract(interval);
1200 }; 1195 };
1201 if (current_draw_indirect->include_count) { 1196 if (current_draw_indirect->include_count) {
1202 update(current_draw_indirect->count_start_address, sizeof(u32), 1197 update(current_draw_indirect->count_start_address, sizeof(u32),
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp
index 02e161270..91f10aec2 100644
--- a/src/video_core/engines/fermi_2d.cpp
+++ b/src/video_core/engines/fermi_2d.cpp
@@ -72,7 +72,7 @@ void Fermi2D::Blit() {
72 UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled"); 72 UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled");
73 73
74 const auto& args = regs.pixels_from_memory; 74 const auto& args = regs.pixels_from_memory;
75 constexpr s64 null_derivate = 1ULL << 32; 75 constexpr s64 null_derivative = 1ULL << 32;
76 Surface src = regs.src; 76 Surface src = regs.src;
77 const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); 77 const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
78 const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 && 78 const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 &&
@@ -89,7 +89,7 @@ void Fermi2D::Blit() {
89 .operation = regs.operation, 89 .operation = regs.operation,
90 .filter = args.sample_mode.filter, 90 .filter = args.sample_mode.filter,
91 .must_accelerate = 91 .must_accelerate =
92 args.du_dx != null_derivate || args.dv_dy != null_derivate || delegate_to_gpu, 92 args.du_dx != null_derivative || args.dv_dy != null_derivative || delegate_to_gpu,
93 .dst_x0 = args.dst_x0, 93 .dst_x0 = args.dst_x0,
94 .dst_y0 = args.dst_y0, 94 .dst_y0 = args.dst_y0,
95 .dst_x1 = args.dst_x0 + args.dst_width, 95 .dst_x1 = args.dst_x0 + args.dst_width,
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 32d767d85..592c28ba3 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -268,7 +268,7 @@ size_t Maxwell3D::EstimateIndexBufferSize() {
268 std::numeric_limits<u32>::max()}; 268 std::numeric_limits<u32>::max()};
269 const size_t byte_size = regs.index_buffer.FormatSizeInBytes(); 269 const size_t byte_size = regs.index_buffer.FormatSizeInBytes();
270 const size_t log2_byte_size = Common::Log2Ceil64(byte_size); 270 const size_t log2_byte_size = Common::Log2Ceil64(byte_size);
271 const size_t cap{GetMaxCurrentVertices() * 3 * byte_size}; 271 const size_t cap{GetMaxCurrentVertices() * 4 * byte_size};
272 const size_t lower_cap = 272 const size_t lower_cap =
273 std::min<size_t>(static_cast<size_t>(end_address - start_address), cap); 273 std::min<size_t>(static_cast<size_t>(end_address - start_address), cap);
274 return std::min<size_t>( 274 return std::min<size_t>(
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h
index c0e6471fe..805a89900 100644
--- a/src/video_core/fence_manager.h
+++ b/src/video_core/fence_manager.h
@@ -86,10 +86,7 @@ public:
86 uncommitted_operations.emplace_back(std::move(func)); 86 uncommitted_operations.emplace_back(std::move(func));
87 } 87 }
88 pending_operations.emplace_back(std::move(uncommitted_operations)); 88 pending_operations.emplace_back(std::move(uncommitted_operations));
89 { 89 QueueFence(new_fence);
90 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
91 QueueFence(new_fence);
92 }
93 if (!delay_fence) { 90 if (!delay_fence) {
94 func(); 91 func();
95 } 92 }
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
index 44a771d65..af0a453ee 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
@@ -559,7 +559,9 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
559} 559}
560 560
561void GraphicsPipeline::ConfigureTransformFeedbackImpl() const { 561void GraphicsPipeline::ConfigureTransformFeedbackImpl() const {
562 glTransformFeedbackAttribsNV(num_xfb_attribs, xfb_attribs.data(), GL_SEPARATE_ATTRIBS); 562 const GLenum buffer_mode =
563 num_xfb_buffers_active == 1 ? GL_INTERLEAVED_ATTRIBS : GL_SEPARATE_ATTRIBS;
564 glTransformFeedbackAttribsNV(num_xfb_attribs, xfb_attribs.data(), buffer_mode);
563} 565}
564 566
565void GraphicsPipeline::GenerateTransformFeedbackState() { 567void GraphicsPipeline::GenerateTransformFeedbackState() {
@@ -567,12 +569,14 @@ void GraphicsPipeline::GenerateTransformFeedbackState() {
567 // when this is required. 569 // when this is required.
568 GLint* cursor{xfb_attribs.data()}; 570 GLint* cursor{xfb_attribs.data()};
569 571
572 num_xfb_buffers_active = 0;
570 for (size_t feedback = 0; feedback < Maxwell::NumTransformFeedbackBuffers; ++feedback) { 573 for (size_t feedback = 0; feedback < Maxwell::NumTransformFeedbackBuffers; ++feedback) {
571 const auto& layout = key.xfb_state.layouts[feedback]; 574 const auto& layout = key.xfb_state.layouts[feedback];
572 UNIMPLEMENTED_IF_MSG(layout.stride != layout.varying_count * 4, "Stride padding"); 575 UNIMPLEMENTED_IF_MSG(layout.stride != layout.varying_count * 4, "Stride padding");
573 if (layout.varying_count == 0) { 576 if (layout.varying_count == 0) {
574 continue; 577 continue;
575 } 578 }
579 num_xfb_buffers_active++;
576 580
577 const auto& locations = key.xfb_state.varyings[feedback]; 581 const auto& locations = key.xfb_state.varyings[feedback];
578 std::optional<u32> current_index; 582 std::optional<u32> current_index;
diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.h b/src/video_core/renderer_opengl/gl_graphics_pipeline.h
index 74fc9cc3d..2f70c1ae9 100644
--- a/src/video_core/renderer_opengl/gl_graphics_pipeline.h
+++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.h
@@ -154,6 +154,7 @@ private:
154 154
155 static constexpr std::size_t XFB_ENTRY_STRIDE = 3; 155 static constexpr std::size_t XFB_ENTRY_STRIDE = 3;
156 GLsizei num_xfb_attribs{}; 156 GLsizei num_xfb_attribs{};
157 u32 num_xfb_buffers_active{};
157 std::array<GLint, 128 * XFB_ENTRY_STRIDE * Maxwell::NumTransformFeedbackBuffers> xfb_attribs{}; 158 std::array<GLint, 128 * XFB_ENTRY_STRIDE * Maxwell::NumTransformFeedbackBuffers> xfb_attribs{};
158 159
159 std::mutex built_mutex; 160 std::mutex built_mutex;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 27e2de1bf..9995b6dd4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -555,7 +555,7 @@ void RasterizerOpenGL::OnCacheInvalidation(VAddr addr, u64 size) {
555 } 555 }
556 { 556 {
557 std::scoped_lock lock{buffer_cache.mutex}; 557 std::scoped_lock lock{buffer_cache.mutex};
558 buffer_cache.CachedWriteMemory(addr, size); 558 buffer_cache.WriteMemory(addr, size);
559 } 559 }
560 shader_cache.InvalidateRegion(addr, size); 560 shader_cache.InvalidateRegion(addr, size);
561} 561}
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index 7e7a80740..c4c30d807 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -132,16 +132,12 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
132 const bool use_accelerated = 132 const bool use_accelerated =
133 rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); 133 rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
134 const bool is_srgb = use_accelerated && screen_info.is_srgb; 134 const bool is_srgb = use_accelerated && screen_info.is_srgb;
135 RenderScreenshot(*framebuffer, use_accelerated);
135 136
136 { 137 Frame* frame = present_manager.GetRenderFrame();
137 std::scoped_lock lock{rasterizer.LockCaches()}; 138 blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
138 RenderScreenshot(*framebuffer, use_accelerated); 139 scheduler.Flush(*frame->render_ready);
139 140 present_manager.Present(frame);
140 Frame* frame = present_manager.GetRenderFrame();
141 blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
142 scheduler.Flush(*frame->render_ready);
143 present_manager.Present(frame);
144 }
145 141
146 gpu.RendererFrameEndNotify(); 142 gpu.RendererFrameEndNotify();
147 rasterizer.TickFrame(); 143 rasterizer.TickFrame();
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index c0e8431e4..e0ab1eaac 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -199,7 +199,7 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
199 if (!pipeline) { 199 if (!pipeline) {
200 return; 200 return;
201 } 201 }
202 std::scoped_lock lock{LockCaches()}; 202 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
203 // update engine as channel may be different. 203 // update engine as channel may be different.
204 pipeline->SetEngine(maxwell3d, gpu_memory); 204 pipeline->SetEngine(maxwell3d, gpu_memory);
205 pipeline->Configure(is_indexed); 205 pipeline->Configure(is_indexed);
@@ -621,7 +621,7 @@ void RasterizerVulkan::OnCacheInvalidation(VAddr addr, u64 size) {
621 } 621 }
622 { 622 {
623 std::scoped_lock lock{buffer_cache.mutex}; 623 std::scoped_lock lock{buffer_cache.mutex};
624 buffer_cache.CachedWriteMemory(addr, size); 624 buffer_cache.WriteMemory(addr, size);
625 } 625 }
626 pipeline_cache.InvalidateRegion(addr, size); 626 pipeline_cache.InvalidateRegion(addr, size);
627} 627}
@@ -710,7 +710,6 @@ void RasterizerVulkan::TiledCacheBarrier() {
710} 710}
711 711
712void RasterizerVulkan::FlushCommands() { 712void RasterizerVulkan::FlushCommands() {
713 std::scoped_lock lock{LockCaches()};
714 if (draw_counter == 0) { 713 if (draw_counter == 0) {
715 return; 714 return;
716 } 715 }
@@ -808,7 +807,6 @@ void RasterizerVulkan::FlushWork() {
808 if ((++draw_counter & 7) != 7) { 807 if ((++draw_counter & 7) != 7) {
809 return; 808 return;
810 } 809 }
811 std::scoped_lock lock{LockCaches()};
812 if (draw_counter < DRAWS_TO_DISPATCH) { 810 if (draw_counter < DRAWS_TO_DISPATCH) {
813 // Send recorded tasks to the worker thread 811 // Send recorded tasks to the worker thread
814 scheduler.DispatchWork(); 812 scheduler.DispatchWork();
@@ -1507,7 +1505,7 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
1507void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) { 1505void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {
1508 CreateChannel(channel); 1506 CreateChannel(channel);
1509 { 1507 {
1510 std::scoped_lock lock{LockCaches()}; 1508 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
1511 texture_cache.CreateChannel(channel); 1509 texture_cache.CreateChannel(channel);
1512 buffer_cache.CreateChannel(channel); 1510 buffer_cache.CreateChannel(channel);
1513 } 1511 }
@@ -1520,7 +1518,7 @@ void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) {
1520 const s32 channel_id = channel.bind_id; 1518 const s32 channel_id = channel.bind_id;
1521 BindToChannel(channel_id); 1519 BindToChannel(channel_id);
1522 { 1520 {
1523 std::scoped_lock lock{LockCaches()}; 1521 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
1524 texture_cache.BindToChannel(channel_id); 1522 texture_cache.BindToChannel(channel_id);
1525 buffer_cache.BindToChannel(channel_id); 1523 buffer_cache.BindToChannel(channel_id);
1526 } 1524 }
@@ -1533,7 +1531,7 @@ void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) {
1533void RasterizerVulkan::ReleaseChannel(s32 channel_id) { 1531void RasterizerVulkan::ReleaseChannel(s32 channel_id) {
1534 EraseChannel(channel_id); 1532 EraseChannel(channel_id);
1535 { 1533 {
1536 std::scoped_lock lock{LockCaches()}; 1534 std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
1537 texture_cache.EraseChannel(channel_id); 1535 texture_cache.EraseChannel(channel_id);
1538 buffer_cache.EraseChannel(channel_id); 1536 buffer_cache.EraseChannel(channel_id);
1539 } 1537 }
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index ce3dfbaab..ad069556c 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -133,10 +133,6 @@ public:
133 133
134 void ReleaseChannel(s32 channel_id) override; 134 void ReleaseChannel(s32 channel_id) override;
135 135
136 std::scoped_lock<std::recursive_mutex, std::recursive_mutex> LockCaches() {
137 return std::scoped_lock{buffer_cache.mutex, texture_cache.mutex};
138 }
139
140private: 136private:
141 static constexpr size_t MAX_TEXTURES = 192; 137 static constexpr size_t MAX_TEXTURES = 192;
142 static constexpr size_t MAX_IMAGES = 48; 138 static constexpr size_t MAX_IMAGES = 48;
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index 515cb7ce6..9e5319716 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -13,7 +13,6 @@
13#include "core/hid/hid_core.h" 13#include "core/hid/hid_core.h"
14#include "core/hid/hid_types.h" 14#include "core/hid/hid_types.h"
15#include "core/hle/service/hid/controllers/npad.h" 15#include "core/hle/service/hid/controllers/npad.h"
16#include "core/hle/service/hid/hid.h"
17#include "core/hle/service/sm/sm.h" 16#include "core/hle/service/sm/sm.h"
18#include "ui_qt_controller.h" 17#include "ui_qt_controller.h"
19#include "yuzu/applets/qt_controller.h" 18#include "yuzu/applets/qt_controller.h"
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index baa3e55f3..c0ae6468b 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -35,6 +35,7 @@ const std::array<int, Settings::NativeButton::NumButtons> Config::default_button
35 Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T, 35 Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T,
36 Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, 36 Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right,
37 Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0, 37 Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0,
38 Qt::Key_Q, Qt::Key_E,
38}; 39};
39 40
40const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = { 41const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = {
@@ -360,6 +361,7 @@ void Config::ReadAudioValues() {
360 qt_config->beginGroup(QStringLiteral("Audio")); 361 qt_config->beginGroup(QStringLiteral("Audio"));
361 362
362 ReadCategory(Settings::Category::Audio); 363 ReadCategory(Settings::Category::Audio);
364 ReadCategory(Settings::Category::UiAudio);
363 365
364 qt_config->endGroup(); 366 qt_config->endGroup();
365} 367}
@@ -900,6 +902,7 @@ void Config::SaveAudioValues() {
900 qt_config->beginGroup(QStringLiteral("Audio")); 902 qt_config->beginGroup(QStringLiteral("Audio"));
901 903
902 WriteCategory(Settings::Category::Audio); 904 WriteCategory(Settings::Category::Audio);
905 WriteCategory(Settings::Category::UiAudio);
903 906
904 qt_config->endGroup(); 907 qt_config->endGroup();
905} 908}
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index 81dd51ad3..9b6ef47a7 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -38,17 +38,21 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
38 38
39 std::map<u32, QWidget*> hold; 39 std::map<u32, QWidget*> hold;
40 40
41 auto push = [&](Settings::Category category) { 41 auto push_settings = [&](Settings::Category category) {
42 for (auto* setting : Settings::values.linkage.by_category[category]) { 42 for (auto* setting : Settings::values.linkage.by_category[category]) {
43 settings.push_back(setting); 43 settings.push_back(setting);
44 } 44 }
45 };
46
47 auto push_ui_settings = [&](Settings::Category category) {
45 for (auto* setting : UISettings::values.linkage.by_category[category]) { 48 for (auto* setting : UISettings::values.linkage.by_category[category]) {
46 settings.push_back(setting); 49 settings.push_back(setting);
47 } 50 }
48 }; 51 };
49 52
50 push(Settings::Category::Audio); 53 push_settings(Settings::Category::Audio);
51 push(Settings::Category::SystemAudio); 54 push_settings(Settings::Category::SystemAudio);
55 push_ui_settings(Settings::Category::UiAudio);
52 56
53 for (auto* setting : settings) { 57 for (auto* setting : settings) {
54 auto* widget = builder.BuildWidget(setting, apply_funcs); 58 auto* widget = builder.BuildWidget(setting, apply_funcs);
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 576f5b571..9259e2a5d 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -322,11 +322,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
322 setFocusPolicy(Qt::ClickFocus); 322 setFocusPolicy(Qt::ClickFocus);
323 323
324 button_map = { 324 button_map = {
325 ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, 325 ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
326 ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, 326 ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
327 ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, 327 ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
328 ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, 328 ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
329 ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, 329 ui->buttonSLLeft, ui->buttonSRLeft, ui->buttonHome, ui->buttonScreenshot,
330 ui->buttonSLRight, ui->buttonSRRight,
330 }; 331 };
331 332
332 analog_map_buttons = {{ 333 analog_map_buttons = {{
@@ -1181,10 +1182,13 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1181 1182
1182 // List of all the widgets that will be hidden by any of the following layouts that need 1183 // List of all the widgets that will be hidden by any of the following layouts that need
1183 // "unhidden" after the controller type changes 1184 // "unhidden" after the controller type changes
1184 const std::array<QWidget*, 11> layout_show = { 1185 const std::array<QWidget*, 14> layout_show = {
1185 ui->buttonShoulderButtonsSLSR, 1186 ui->buttonShoulderButtonsSLSRLeft,
1187 ui->buttonShoulderButtonsSLSRRight,
1186 ui->horizontalSpacerShoulderButtonsWidget, 1188 ui->horizontalSpacerShoulderButtonsWidget,
1187 ui->horizontalSpacerShoulderButtonsWidget2, 1189 ui->horizontalSpacerShoulderButtonsWidget2,
1190 ui->horizontalSpacerShoulderButtonsWidget3,
1191 ui->horizontalSpacerShoulderButtonsWidget4,
1188 ui->buttonShoulderButtonsLeft, 1192 ui->buttonShoulderButtonsLeft,
1189 ui->buttonMiscButtonsMinusScreenshot, 1193 ui->buttonMiscButtonsMinusScreenshot,
1190 ui->bottomLeft, 1194 ui->bottomLeft,
@@ -1202,16 +1206,19 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1202 std::vector<QWidget*> layout_hidden; 1206 std::vector<QWidget*> layout_hidden;
1203 switch (layout) { 1207 switch (layout) {
1204 case Core::HID::NpadStyleIndex::ProController: 1208 case Core::HID::NpadStyleIndex::ProController:
1205 case Core::HID::NpadStyleIndex::JoyconDual:
1206 case Core::HID::NpadStyleIndex::Handheld: 1209 case Core::HID::NpadStyleIndex::Handheld:
1207 layout_hidden = { 1210 layout_hidden = {
1208 ui->buttonShoulderButtonsSLSR, 1211 ui->buttonShoulderButtonsSLSRLeft,
1212 ui->buttonShoulderButtonsSLSRRight,
1209 ui->horizontalSpacerShoulderButtonsWidget2, 1213 ui->horizontalSpacerShoulderButtonsWidget2,
1214 ui->horizontalSpacerShoulderButtonsWidget4,
1210 }; 1215 };
1211 break; 1216 break;
1212 case Core::HID::NpadStyleIndex::JoyconLeft: 1217 case Core::HID::NpadStyleIndex::JoyconLeft:
1213 layout_hidden = { 1218 layout_hidden = {
1219 ui->buttonShoulderButtonsSLSRRight,
1214 ui->horizontalSpacerShoulderButtonsWidget2, 1220 ui->horizontalSpacerShoulderButtonsWidget2,
1221 ui->horizontalSpacerShoulderButtonsWidget3,
1215 ui->buttonShoulderButtonsRight, 1222 ui->buttonShoulderButtonsRight,
1216 ui->buttonMiscButtonsPlusHome, 1223 ui->buttonMiscButtonsPlusHome,
1217 ui->bottomRight, 1224 ui->bottomRight,
@@ -1219,16 +1226,17 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
1219 break; 1226 break;
1220 case Core::HID::NpadStyleIndex::JoyconRight: 1227 case Core::HID::NpadStyleIndex::JoyconRight:
1221 layout_hidden = { 1228 layout_hidden = {
1222 ui->horizontalSpacerShoulderButtonsWidget, 1229 ui->buttonShoulderButtonsSLSRLeft, ui->horizontalSpacerShoulderButtonsWidget,
1223 ui->buttonShoulderButtonsLeft, 1230 ui->horizontalSpacerShoulderButtonsWidget4, ui->buttonShoulderButtonsLeft,
1224 ui->buttonMiscButtonsMinusScreenshot, 1231 ui->buttonMiscButtonsMinusScreenshot, ui->bottomLeft,
1225 ui->bottomLeft,
1226 }; 1232 };
1227 break; 1233 break;
1228 case Core::HID::NpadStyleIndex::GameCube: 1234 case Core::HID::NpadStyleIndex::GameCube:
1229 layout_hidden = { 1235 layout_hidden = {
1230 ui->buttonShoulderButtonsSLSR, 1236 ui->buttonShoulderButtonsSLSRLeft,
1237 ui->buttonShoulderButtonsSLSRRight,
1231 ui->horizontalSpacerShoulderButtonsWidget2, 1238 ui->horizontalSpacerShoulderButtonsWidget2,
1239 ui->horizontalSpacerShoulderButtonsWidget4,
1232 ui->buttonMiscButtonsMinusGroup, 1240 ui->buttonMiscButtonsMinusGroup,
1233 ui->buttonMiscButtonsScreenshotGroup, 1241 ui->buttonMiscButtonsScreenshotGroup,
1234 }; 1242 };
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui
index 611a79477..5518cccd1 100644
--- a/src/yuzu/configuration/configure_input_player.ui
+++ b/src/yuzu/configuration/configure_input_player.ui
@@ -1208,6 +1208,159 @@
1208 <property name="spacing"> 1208 <property name="spacing">
1209 <number>3</number> 1209 <number>3</number>
1210 </property> 1210 </property>
1211 <item>
1212 <widget class="QWidget" name="buttonShoulderButtonsSLSRLeft" native="true">
1213 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRLeftVerticalLayout">
1214 <property name="spacing">
1215 <number>0</number>
1216 </property>
1217 <property name="leftMargin">
1218 <number>0</number>
1219 </property>
1220 <property name="topMargin">
1221 <number>0</number>
1222 </property>
1223 <property name="rightMargin">
1224 <number>0</number>
1225 </property>
1226 <property name="bottomMargin">
1227 <number>0</number>
1228 </property>
1229 <item alignment="Qt::AlignHCenter">
1230 <widget class="QGroupBox" name="buttonShoulderButtonsSLLeftGroup">
1231 <property name="title">
1232 <string>SL</string>
1233 </property>
1234 <property name="alignment">
1235 <set>Qt::AlignCenter</set>
1236 </property>
1237 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLLeftVerticalLayout">
1238 <property name="spacing">
1239 <number>3</number>
1240 </property>
1241 <property name="leftMargin">
1242 <number>3</number>
1243 </property>
1244 <property name="topMargin">
1245 <number>3</number>
1246 </property>
1247 <property name="rightMargin">
1248 <number>3</number>
1249 </property>
1250 <property name="bottomMargin">
1251 <number>3</number>
1252 </property>
1253 <item>
1254 <widget class="QPushButton" name="buttonSLLeft">
1255 <property name="minimumSize">
1256 <size>
1257 <width>68</width>
1258 <height>0</height>
1259 </size>
1260 </property>
1261 <property name="maximumSize">
1262 <size>
1263 <width>68</width>
1264 <height>16777215</height>
1265 </size>
1266 </property>
1267 <property name="styleSheet">
1268 <string notr="true">min-width: 68px;</string>
1269 </property>
1270 <property name="text">
1271 <string>SL</string>
1272 </property>
1273 </widget>
1274 </item>
1275 </layout>
1276 </widget>
1277 </item>
1278 <item alignment="Qt::AlignHCenter">
1279 <widget class="QGroupBox" name="buttonShoulderButtonsSRLeftGroup">
1280 <property name="title">
1281 <string>SR</string>
1282 </property>
1283 <property name="alignment">
1284 <set>Qt::AlignCenter</set>
1285 </property>
1286 <layout class="QVBoxLayout" name="buttonShoulderButtonsSRLeftVerticalLayout">
1287 <property name="spacing">
1288 <number>3</number>
1289 </property>
1290 <property name="leftMargin">
1291 <number>3</number>
1292 </property>
1293 <property name="topMargin">
1294 <number>3</number>
1295 </property>
1296 <property name="rightMargin">
1297 <number>3</number>
1298 </property>
1299 <property name="bottomMargin">
1300 <number>3</number>
1301 </property>
1302 <item>
1303 <widget class="QPushButton" name="buttonSRLeft">
1304 <property name="minimumSize">
1305 <size>
1306 <width>68</width>
1307 <height>0</height>
1308 </size>
1309 </property>
1310 <property name="maximumSize">
1311 <size>
1312 <width>68</width>
1313 <height>16777215</height>
1314 </size>
1315 </property>
1316 <property name="styleSheet">
1317 <string notr="true">min-width: 68px;</string>
1318 </property>
1319 <property name="text">
1320 <string>SR</string>
1321 </property>
1322 </widget>
1323 </item>
1324 </layout>
1325 </widget>
1326 </item>
1327 </layout>
1328 </widget>
1329 </item>
1330 <item>
1331 <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget4" native="true">
1332 <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidget4Layout">
1333 <property name="spacing">
1334 <number>0</number>
1335 </property>
1336 <property name="leftMargin">
1337 <number>0</number>
1338 </property>
1339 <property name="topMargin">
1340 <number>0</number>
1341 </property>
1342 <property name="rightMargin">
1343 <number>0</number>
1344 </property>
1345 <property name="bottomMargin">
1346 <number>0</number>
1347 </property>
1348 <item>
1349 <spacer name="horizontalSpacerShoulderButtons5">
1350 <property name="orientation">
1351 <enum>Qt::Horizontal</enum>
1352 </property>
1353 <property name="sizeHint" stdset="0">
1354 <size>
1355 <width>0</width>
1356 <height>20</height>
1357 </size>
1358 </property>
1359 </spacer>
1360 </item>
1361 </layout>
1362 </widget>
1363 </item>
1211 <item> 1364 <item>
1212 <widget class="QWidget" name="buttonShoulderButtonsLeft" native="true"> 1365 <widget class="QWidget" name="buttonShoulderButtonsLeft" native="true">
1213 <layout class="QVBoxLayout" name="buttonShoulderButtonsLeftVerticalLayout"> 1366 <layout class="QVBoxLayout" name="buttonShoulderButtonsLeftVerticalLayout">
@@ -1830,125 +1983,125 @@
1830 </layout> 1983 </layout>
1831 </widget> 1984 </widget>
1832 </item> 1985 </item>
1833 <item> 1986 <item>
1834 <widget class="QWidget" name="buttonShoulderButtonsSLSR" native="true"> 1987 <widget class="QWidget" name="buttonShoulderButtonsSLSRRight" native="true">
1835 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRVerticalLayout"> 1988 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRRightVerticalLayout">
1836 <property name="spacing"> 1989 <property name="spacing">
1837 <number>0</number> 1990 <number>0</number>
1838 </property> 1991 </property>
1839 <property name="leftMargin"> 1992 <property name="leftMargin">
1840 <number>0</number> 1993 <number>0</number>
1841 </property> 1994 </property>
1842 <property name="topMargin"> 1995 <property name="topMargin">
1843 <number>0</number> 1996 <number>0</number>
1844 </property> 1997 </property>
1845 <property name="rightMargin"> 1998 <property name="rightMargin">
1846 <number>0</number> 1999 <number>0</number>
1847 </property> 2000 </property>
1848 <property name="bottomMargin"> 2001 <property name="bottomMargin">
1849 <number>0</number> 2002 <number>0</number>
1850 </property> 2003 </property>
1851 <item alignment="Qt::AlignHCenter"> 2004 <item alignment="Qt::AlignHCenter">
1852 <widget class="QGroupBox" name="buttonShoulderButtonsSLGroup"> 2005 <widget class="QGroupBox" name="buttonShoulderButtonsSLRightGroup">
1853 <property name="title"> 2006 <property name="title">
1854 <string>SL</string> 2007 <string>SL</string>
1855 </property> 2008 </property>
1856 <property name="alignment"> 2009 <property name="alignment">
1857 <set>Qt::AlignCenter</set> 2010 <set>Qt::AlignCenter</set>
1858 </property> 2011 </property>
1859 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout"> 2012 <layout class="QVBoxLayout" name="buttonShoulderButtonsSLRightVerticalLayout">
1860 <property name="spacing"> 2013 <property name="spacing">
1861 <number>3</number> 2014 <number>3</number>
1862 </property> 2015 </property>
1863 <property name="leftMargin"> 2016 <property name="leftMargin">
1864 <number>3</number> 2017 <number>3</number>
1865 </property> 2018 </property>
1866 <property name="topMargin"> 2019 <property name="topMargin">
1867 <number>3</number> 2020 <number>3</number>
1868 </property> 2021 </property>
1869 <property name="rightMargin"> 2022 <property name="rightMargin">
1870 <number>3</number> 2023 <number>3</number>
1871 </property> 2024 </property>
1872 <property name="bottomMargin"> 2025 <property name="bottomMargin">
1873 <number>3</number> 2026 <number>3</number>
1874 </property> 2027 </property>
1875 <item> 2028 <item>
1876 <widget class="QPushButton" name="buttonSL"> 2029 <widget class="QPushButton" name="buttonSLRight">
1877 <property name="minimumSize"> 2030 <property name="minimumSize">
1878 <size> 2031 <size>
1879 <width>68</width> 2032 <width>68</width>
1880 <height>0</height> 2033 <height>0</height>
1881 </size> 2034 </size>
1882 </property> 2035 </property>
1883 <property name="maximumSize"> 2036 <property name="maximumSize">
1884 <size> 2037 <size>
1885 <width>68</width> 2038 <width>68</width>
1886 <height>16777215</height> 2039 <height>16777215</height>
1887 </size> 2040 </size>
1888 </property> 2041 </property>
1889 <property name="styleSheet"> 2042 <property name="styleSheet">
1890 <string notr="true">min-width: 68px;</string> 2043 <string notr="true">min-width: 68px;</string>
1891 </property> 2044 </property>
1892 <property name="text"> 2045 <property name="text">
1893 <string>SL</string> 2046 <string>SL</string>
1894 </property> 2047 </property>
1895 </widget> 2048 </widget>
1896 </item> 2049 </item>
1897 </layout> 2050 </layout>
1898 </widget> 2051 </widget>
1899 </item> 2052 </item>
1900 <item alignment="Qt::AlignHCenter"> 2053 <item alignment="Qt::AlignHCenter">
1901 <widget class="QGroupBox" name="buttonShoulderButtonsSRGroup"> 2054 <widget class="QGroupBox" name="buttonShoulderButtonsSRRightGroup">
1902 <property name="title"> 2055 <property name="title">
1903 <string>SR</string> 2056 <string>SR</string>
1904 </property> 2057 </property>
1905 <property name="alignment"> 2058 <property name="alignment">
1906 <set>Qt::AlignCenter</set> 2059 <set>Qt::AlignCenter</set>
1907 </property> 2060 </property>
1908 <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout"> 2061 <layout class="QVBoxLayout" name="buttonShoulderButtonsSRRightVerticalLayout">
1909 <property name="spacing"> 2062 <property name="spacing">
1910 <number>3</number> 2063 <number>3</number>
1911 </property> 2064 </property>
1912 <property name="leftMargin"> 2065 <property name="leftMargin">
1913 <number>3</number> 2066 <number>3</number>
1914 </property> 2067 </property>
1915 <property name="topMargin"> 2068 <property name="topMargin">
1916 <number>3</number> 2069 <number>3</number>
1917 </property> 2070 </property>
1918 <property name="rightMargin"> 2071 <property name="rightMargin">
1919 <number>3</number> 2072 <number>3</number>
1920 </property> 2073 </property>
1921 <property name="bottomMargin"> 2074 <property name="bottomMargin">
1922 <number>3</number> 2075 <number>3</number>
1923 </property> 2076 </property>
1924 <item> 2077 <item>
1925 <widget class="QPushButton" name="buttonSR"> 2078 <widget class="QPushButton" name="buttonSRRight">
1926 <property name="minimumSize"> 2079 <property name="minimumSize">
1927 <size> 2080 <size>
1928 <width>68</width> 2081 <width>68</width>
1929 <height>0</height> 2082 <height>0</height>
1930 </size> 2083 </size>
1931 </property> 2084 </property>
1932 <property name="maximumSize"> 2085 <property name="maximumSize">
1933 <size> 2086 <size>
1934 <width>68</width> 2087 <width>68</width>
1935 <height>16777215</height> 2088 <height>16777215</height>
1936 </size> 2089 </size>
1937 </property> 2090 </property>
1938 <property name="styleSheet"> 2091 <property name="styleSheet">
1939 <string notr="true">min-width: 68px;</string> 2092 <string notr="true">min-width: 68px;</string>
1940 </property> 2093 </property>
1941 <property name="text"> 2094 <property name="text">
1942 <string>SR</string> 2095 <string>SR</string>
1943 </property> 2096 </property>
1944 </widget> 2097 </widget>
1945 </item> 2098 </item>
2099 </layout>
2100 </widget>
2101 </item>
1946 </layout> 2102 </layout>
1947 </widget> 2103 </widget>
1948 </item> 2104 </item>
1949 </layout>
1950 </widget>
1951 </item>
1952 </layout> 2105 </layout>
1953 </item> 2106 </item>
1954 <item> 2107 <item>
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index a188eef92..550cff9a0 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -297,8 +297,8 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
297 297
298 // Sideview SL and SR buttons 298 // Sideview SL and SR buttons
299 button_color = colors.slider_button; 299 button_color = colors.slider_button;
300 DrawRoundButton(p, center + QPoint(59, 52), button_values[SR], 5, 12, Direction::Left); 300 DrawRoundButton(p, center + QPoint(59, 52), button_values[SRLeft], 5, 12, Direction::Left);
301 DrawRoundButton(p, center + QPoint(59, -69), button_values[SL], 5, 12, Direction::Left); 301 DrawRoundButton(p, center + QPoint(59, -69), button_values[SLLeft], 5, 12, Direction::Left);
302 302
303 DrawLeftBody(p, center); 303 DrawLeftBody(p, center);
304 304
@@ -353,8 +353,10 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
353 // SR and SL buttons 353 // SR and SL buttons
354 p.setPen(colors.outline); 354 p.setPen(colors.outline);
355 button_color = colors.slider_button; 355 button_color = colors.slider_button;
356 DrawRoundButton(p, center + QPoint(155, 52), button_values[SR], 5.2f, 12, Direction::None, 4); 356 DrawRoundButton(p, center + QPoint(155, 52), button_values[SRLeft], 5.2f, 12, Direction::None,
357 DrawRoundButton(p, center + QPoint(155, -69), button_values[SL], 5.2f, 12, Direction::None, 4); 357 4);
358 DrawRoundButton(p, center + QPoint(155, -69), button_values[SLLeft], 5.2f, 12, Direction::None,
359 4);
358 360
359 // SR and SL text 361 // SR and SL text
360 p.setPen(colors.transparent); 362 p.setPen(colors.transparent);
@@ -428,8 +430,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
428 430
429 // Sideview SL and SR buttons 431 // Sideview SL and SR buttons
430 button_color = colors.slider_button; 432 button_color = colors.slider_button;
431 DrawRoundButton(p, center + QPoint(-59, 52), button_values[SL], 5, 11, Direction::Right); 433 DrawRoundButton(p, center + QPoint(-59, 52), button_values[SLRight], 5, 11,
432 DrawRoundButton(p, center + QPoint(-59, -69), button_values[SR], 5, 11, Direction::Right); 434 Direction::Right);
435 DrawRoundButton(p, center + QPoint(-59, -69), button_values[SRRight], 5, 11,
436 Direction::Right);
433 437
434 DrawRightBody(p, center); 438 DrawRightBody(p, center);
435 439
@@ -484,8 +488,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
484 // SR and SL buttons 488 // SR and SL buttons
485 p.setPen(colors.outline); 489 p.setPen(colors.outline);
486 button_color = colors.slider_button; 490 button_color = colors.slider_button;
487 DrawRoundButton(p, center + QPoint(-155, 52), button_values[SL], 5, 12, Direction::None, 4.0f); 491 DrawRoundButton(p, center + QPoint(-155, 52), button_values[SLRight], 5, 12, Direction::None,
488 DrawRoundButton(p, center + QPoint(-155, -69), button_values[SR], 5, 12, Direction::None, 4.0f); 492 4.0f);
493 DrawRoundButton(p, center + QPoint(-155, -69), button_values[SRRight], 5, 12, Direction::None,
494 4.0f);
489 495
490 // SR and SL text 496 // SR and SL text
491 p.setPen(colors.transparent); 497 p.setPen(colors.transparent);
@@ -557,6 +563,19 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
557 DrawRoundButton(p, center + QPoint(-154, -72), button_values[Minus], 7, 4, Direction::Up, 563 DrawRoundButton(p, center + QPoint(-154, -72), button_values[Minus], 7, 4, Direction::Up,
558 1); 564 1);
559 565
566 // Left SR and SL sideview buttons
567 button_color = colors.slider_button;
568 DrawRoundButton(p, center + QPoint(-20, -62), button_values[SLLeft], 4, 11,
569 Direction::Left);
570 DrawRoundButton(p, center + QPoint(-20, 47), button_values[SRLeft], 4, 11, Direction::Left);
571
572 // Right SR and SL sideview buttons
573 button_color = colors.slider_button;
574 DrawRoundButton(p, center + QPoint(20, 47), button_values[SLRight], 4, 11,
575 Direction::Right);
576 DrawRoundButton(p, center + QPoint(20, -62), button_values[SRRight], 4, 11,
577 Direction::Right);
578
560 DrawDualBody(p, center); 579 DrawDualBody(p, center);
561 580
562 // Right trigger top view 581 // Right trigger top view
@@ -1792,16 +1811,6 @@ void PlayerControlPreview::DrawDualBody(QPainter& p, const QPointF center) {
1792 p.setBrush(colors.right); 1811 p.setBrush(colors.right);
1793 DrawPolygon(p, qright_joycon_topview); 1812 DrawPolygon(p, qright_joycon_topview);
1794 1813
1795 // Right SR and SL sideview buttons
1796 p.setPen(colors.outline);
1797 p.setBrush(colors.slider_button);
1798 DrawRoundRectangle(p, center + QPoint(19, 47), 7, 22, 1);
1799 DrawRoundRectangle(p, center + QPoint(19, -62), 7, 22, 1);
1800
1801 // Left SR and SL sideview buttons
1802 DrawRoundRectangle(p, center + QPoint(-19, 47), 7, 22, 1);
1803 DrawRoundRectangle(p, center + QPoint(-19, -62), 7, 22, 1);
1804
1805 // Right Sideview body 1814 // Right Sideview body
1806 p.setBrush(colors.slider); 1815 p.setBrush(colors.slider);
1807 DrawPolygon(p, qright_joycon_slider); 1816 DrawPolygon(p, qright_joycon_slider);
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 7e7d8e252..f294dc23d 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -567,9 +567,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
567 QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity")); 567 QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity"));
568 QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); 568 QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
569 QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); 569 QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
570// TODO: Implement shortcut creation for macOS
571#if !defined(__APPLE__)
570 QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut")); 572 QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut"));
571 QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop")); 573 QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop"));
572#ifndef WIN32
573 QAction* create_applications_menu_shortcut = 574 QAction* create_applications_menu_shortcut =
574 shortcut_menu->addAction(tr("Add to Applications Menu")); 575 shortcut_menu->addAction(tr("Add to Applications Menu"));
575#endif 576#endif
@@ -647,10 +648,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
647 connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { 648 connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
648 emit NavigateToGamedbEntryRequested(program_id, compatibility_list); 649 emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
649 }); 650 });
651// TODO: Implement shortcut creation for macOS
652#if !defined(__APPLE__)
650 connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() { 653 connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() {
651 emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop); 654 emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop);
652 }); 655 });
653#ifndef WIN32
654 connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() { 656 connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() {
655 emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications); 657 emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications);
656 }); 658 });
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index d2a054eaa..f6b548fd3 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -10,6 +10,7 @@
10#include <thread> 10#include <thread>
11#include "core/loader/nca.h" 11#include "core/loader/nca.h"
12#include "core/tools/renderdoc.h" 12#include "core/tools/renderdoc.h"
13
13#ifdef __APPLE__ 14#ifdef __APPLE__
14#include <unistd.h> // for chdir 15#include <unistd.h> // for chdir
15#endif 16#endif
@@ -1064,12 +1065,6 @@ void GMainWindow::InitializeWidgets() {
1064 volume_slider->setObjectName(QStringLiteral("volume_slider")); 1065 volume_slider->setObjectName(QStringLiteral("volume_slider"));
1065 volume_slider->setMaximum(200); 1066 volume_slider->setMaximum(200);
1066 volume_slider->setPageStep(5); 1067 volume_slider->setPageStep(5);
1067 connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) {
1068 Settings::values.audio_muted = false;
1069 const auto volume = static_cast<u8>(percentage);
1070 Settings::values.volume.SetValue(volume);
1071 UpdateVolumeUI();
1072 });
1073 volume_popup->layout()->addWidget(volume_slider); 1068 volume_popup->layout()->addWidget(volume_slider);
1074 1069
1075 volume_button = new VolumeButton(); 1070 volume_button = new VolumeButton();
@@ -1077,6 +1072,12 @@ void GMainWindow::InitializeWidgets() {
1077 volume_button->setFocusPolicy(Qt::NoFocus); 1072 volume_button->setFocusPolicy(Qt::NoFocus);
1078 volume_button->setCheckable(true); 1073 volume_button->setCheckable(true);
1079 UpdateVolumeUI(); 1074 UpdateVolumeUI();
1075 connect(volume_slider, &QSlider::valueChanged, this, [this](int percentage) {
1076 Settings::values.audio_muted = false;
1077 const auto volume = static_cast<u8>(percentage);
1078 Settings::values.volume.SetValue(volume);
1079 UpdateVolumeUI();
1080 });
1080 connect(volume_button, &QPushButton::clicked, this, [&] { 1081 connect(volume_button, &QPushButton::clicked, this, [&] {
1081 UpdateVolumeUI(); 1082 UpdateVolumeUI();
1082 volume_popup->setVisible(!volume_popup->isVisible()); 1083 volume_popup->setVisible(!volume_popup->isVisible());
@@ -2847,170 +2848,259 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,
2847 QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory)); 2848 QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory));
2848} 2849}
2849 2850
2850void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path, 2851bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
2851 GameListShortcutTarget target) { 2852 const std::string& comment,
2852 // Get path to yuzu executable 2853 const std::filesystem::path& icon_path,
2853 const QStringList args = QApplication::arguments(); 2854 const std::filesystem::path& command,
2854 std::filesystem::path yuzu_command = args[0].toStdString(); 2855 const std::string& arguments, const std::string& categories,
2855 2856 const std::string& keywords, const std::string& name) try {
2856 // If relative path, make it an absolute path 2857#if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD
2857 if (yuzu_command.c_str()[0] == '.') { 2858 std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop");
2858 yuzu_command = Common::FS::GetCurrentDir() / yuzu_command; 2859 std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc);
2860 if (!shortcut_stream.is_open()) {
2861 LOG_ERROR(Frontend, "Failed to create shortcut");
2862 return false;
2859 } 2863 }
2860 2864 // TODO: Migrate fmt::print to std::print in futures STD C++ 23.
2861#if defined(__linux__) 2865 fmt::print(shortcut_stream, "[Desktop Entry]\n");
2862 // Warn once if we are making a shortcut to a volatile AppImage 2866 fmt::print(shortcut_stream, "Type=Application\n");
2863 const std::string appimage_ending = 2867 fmt::print(shortcut_stream, "Version=1.0\n");
2864 std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage"); 2868 fmt::print(shortcut_stream, "Name={}\n", name);
2865 if (yuzu_command.string().ends_with(appimage_ending) && 2869 if (!comment.empty()) {
2866 !UISettings::values.shortcut_already_warned) { 2870 fmt::print(shortcut_stream, "Comment={}\n", comment);
2867 if (QMessageBox::warning(this, tr("Create Shortcut"), 2871 }
2868 tr("This will create a shortcut to the current AppImage. This may " 2872 if (std::filesystem::is_regular_file(icon_path)) {
2869 "not work well if you update. Continue?"), 2873 fmt::print(shortcut_stream, "Icon={}\n", icon_path.string());
2870 QMessageBox::StandardButton::Ok | 2874 }
2871 QMessageBox::StandardButton::Cancel) == 2875 fmt::print(shortcut_stream, "TryExec={}\n", command.string());
2872 QMessageBox::StandardButton::Cancel) { 2876 fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments);
2873 return; 2877 if (!categories.empty()) {
2878 fmt::print(shortcut_stream, "Categories={}\n", categories);
2879 }
2880 if (!keywords.empty()) {
2881 fmt::print(shortcut_stream, "Keywords={}\n", keywords);
2882 }
2883 return true;
2884#elif defined(_WIN32) // Windows
2885 HRESULT hr = CoInitialize(nullptr);
2886 if (FAILED(hr)) {
2887 LOG_ERROR(Frontend, "CoInitialize failed");
2888 return false;
2889 }
2890 SCOPE_EXIT({ CoUninitialize(); });
2891 IShellLinkW* ps1 = nullptr;
2892 IPersistFile* persist_file = nullptr;
2893 SCOPE_EXIT({
2894 if (persist_file != nullptr) {
2895 persist_file->Release();
2874 } 2896 }
2875 UISettings::values.shortcut_already_warned = true; 2897 if (ps1 != nullptr) {
2898 ps1->Release();
2899 }
2900 });
2901 HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
2902 reinterpret_cast<void**>(&ps1));
2903 if (FAILED(hres)) {
2904 LOG_ERROR(Frontend, "Failed to create IShellLinkW instance");
2905 return false;
2876 } 2906 }
2877#endif // __linux__ 2907 hres = ps1->SetPath(command.c_str());
2878 2908 if (FAILED(hres)) {
2879 std::filesystem::path target_directory{}; 2909 LOG_ERROR(Frontend, "Failed to set path");
2880 2910 return false;
2881 switch (target) {
2882 case GameListShortcutTarget::Desktop: {
2883 const QString desktop_path =
2884 QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
2885 target_directory = desktop_path.toUtf8().toStdString();
2886 break;
2887 } 2911 }
2888 case GameListShortcutTarget::Applications: { 2912 if (!arguments.empty()) {
2889 const QString applications_path = 2913 hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data());
2890 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); 2914 if (FAILED(hres)) {
2891 if (applications_path.isEmpty()) { 2915 LOG_ERROR(Frontend, "Failed to set arguments");
2892 const char* home = std::getenv("HOME"); 2916 return false;
2893 if (home != nullptr) {
2894 target_directory = std::filesystem::path(home) / ".local/share/applications";
2895 }
2896 } else {
2897 target_directory = applications_path.toUtf8().toStdString();
2898 } 2917 }
2899 break;
2900 } 2918 }
2901 default: 2919 if (!comment.empty()) {
2902 return; 2920 hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data());
2921 if (FAILED(hres)) {
2922 LOG_ERROR(Frontend, "Failed to set description");
2923 return false;
2924 }
2903 } 2925 }
2904 2926 if (std::filesystem::is_regular_file(icon_path)) {
2905 const QDir dir(QString::fromStdString(target_directory.generic_string())); 2927 hres = ps1->SetIconLocation(icon_path.c_str(), 0);
2906 if (!dir.exists()) { 2928 if (FAILED(hres)) {
2907 QMessageBox::critical(this, tr("Create Shortcut"), 2929 LOG_ERROR(Frontend, "Failed to set icon location");
2908 tr("Cannot create shortcut. Path \"%1\" does not exist.") 2930 return false;
2909 .arg(QString::fromStdString(target_directory.generic_string())), 2931 }
2910 QMessageBox::StandardButton::Ok);
2911 return;
2912 } 2932 }
2933 hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&persist_file));
2934 if (FAILED(hres)) {
2935 LOG_ERROR(Frontend, "Failed to get IPersistFile interface");
2936 return false;
2937 }
2938 hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE);
2939 if (FAILED(hres)) {
2940 LOG_ERROR(Frontend, "Failed to save shortcut");
2941 return false;
2942 }
2943 return true;
2944#else // Unsupported platform
2945 return false;
2946#endif
2947} catch (const std::exception& e) {
2948 LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what());
2949 return false;
2950}
2951// Messages in pre-defined message boxes for less code spaghetti
2952bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) {
2953 int result = 0;
2954 QMessageBox::StandardButtons buttons;
2955 switch (imsg) {
2956 case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES:
2957 buttons = QMessageBox::Yes | QMessageBox::No;
2958 result =
2959 QMessageBox::information(parent, tr("Create Shortcut"),
2960 tr("Do you want to launch the game in fullscreen?"), buttons);
2961 return result == QMessageBox::Yes;
2962 case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS:
2963 QMessageBox::information(parent, tr("Create Shortcut"),
2964 tr("Successfully created a shortcut to %1").arg(game_title));
2965 return false;
2966 case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING:
2967 buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel;
2968 result =
2969 QMessageBox::warning(this, tr("Create Shortcut"),
2970 tr("This will create a shortcut to the current AppImage. This may "
2971 "not work well if you update. Continue?"),
2972 buttons);
2973 return result == QMessageBox::Ok;
2974 default:
2975 buttons = QMessageBox::Ok;
2976 QMessageBox::critical(parent, tr("Create Shortcut"),
2977 tr("Failed to create a shortcut to %1").arg(game_title), buttons);
2978 return false;
2979 }
2980}
2913 2981
2914 const std::string game_file_name = std::filesystem::path(game_path).filename().string(); 2982bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
2915 // Determine full paths for icon and shortcut 2983 std::filesystem::path& out_icon_path) {
2916#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) 2984 // Get path to Yuzu icons directory & icon extension
2917 const char* home = std::getenv("HOME"); 2985 std::string ico_extension = "png";
2918 const std::filesystem::path home_path = (home == nullptr ? "~" : home); 2986#if defined(_WIN32)
2919 const char* xdg_data_home = std::getenv("XDG_DATA_HOME"); 2987 out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::IconsDir);
2920 2988 ico_extension = "ico";
2921 std::filesystem::path system_icons_path = 2989#elif defined(__linux__) || defined(__FreeBSD__)
2922 (xdg_data_home == nullptr ? home_path / ".local/share/" 2990 out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256";
2923 : std::filesystem::path(xdg_data_home)) / 2991#endif
2924 "icons/hicolor/256x256"; 2992 // Create icons directory if it doesn't exist
2925 if (!Common::FS::CreateDirs(system_icons_path)) { 2993 if (!Common::FS::CreateDirs(out_icon_path)) {
2926 QMessageBox::critical( 2994 QMessageBox::critical(
2927 this, tr("Create Icon"), 2995 this, tr("Create Icon"),
2928 tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.") 2996 tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.")
2929 .arg(QString::fromStdString(system_icons_path)), 2997 .arg(QString::fromStdString(out_icon_path.string())),
2930 QMessageBox::StandardButton::Ok); 2998 QMessageBox::StandardButton::Ok);
2931 return; 2999 out_icon_path.clear();
3000 return false;
2932 } 3001 }
2933 std::filesystem::path icon_path =
2934 system_icons_path / (program_id == 0 ? fmt::format("yuzu-{}.png", game_file_name)
2935 : fmt::format("yuzu-{:016X}.png", program_id));
2936 const std::filesystem::path shortcut_path =
2937 target_directory / (program_id == 0 ? fmt::format("yuzu-{}.desktop", game_file_name)
2938 : fmt::format("yuzu-{:016X}.desktop", program_id));
2939#elif defined(WIN32)
2940 std::filesystem::path icons_path =
2941 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::IconsDir);
2942 std::filesystem::path icon_path =
2943 icons_path / ((program_id == 0 ? fmt::format("yuzu-{}.ico", game_file_name)
2944 : fmt::format("yuzu-{:016X}.ico", program_id)));
2945#else
2946 std::string icon_extension;
2947#endif
2948
2949 // Get title from game file
2950 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
2951 system->GetContentProvider()};
2952 const auto control = pm.GetControlMetadata();
2953 const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read));
2954 3002
2955 std::string title{fmt::format("{:016X}", program_id)}; 3003 // Create icon file path
2956 3004 out_icon_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension)
2957 if (control.first != nullptr) { 3005 : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension));
2958 title = control.first->GetApplicationName(); 3006 return true;
2959 } else { 3007}
2960 loader->ReadTitle(title);
2961 }
2962 3008
2963 // Get icon from game file 3009void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
2964 std::vector<u8> icon_image_file{}; 3010 GameListShortcutTarget target) {
2965 if (control.second != nullptr) { 3011 std::string game_title;
2966 icon_image_file = control.second->ReadAllBytes(); 3012 QString qt_game_title;
2967 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) { 3013 std::filesystem::path out_icon_path;
2968 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path); 3014 // Get path to yuzu executable
3015 const QStringList args = QApplication::arguments();
3016 std::filesystem::path yuzu_command = args[0].toStdString();
3017 // If relative path, make it an absolute path
3018 if (yuzu_command.c_str()[0] == '.') {
3019 yuzu_command = Common::FS::GetCurrentDir() / yuzu_command;
2969 } 3020 }
2970 3021 // Shortcut path
2971 QImage icon_data = 3022 std::filesystem::path shortcut_path{};
2972 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size())); 3023 if (target == GameListShortcutTarget::Desktop) {
2973#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) 3024 shortcut_path =
2974 // Convert and write the icon as a PNG 3025 QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString();
2975 if (!icon_data.save(QString::fromStdString(icon_path.string()))) { 3026 } else if (target == GameListShortcutTarget::Applications) {
2976 LOG_ERROR(Frontend, "Could not write icon as PNG to file"); 3027 shortcut_path =
3028 QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
3029 }
3030 // Icon path and title
3031 if (std::filesystem::exists(shortcut_path)) {
3032 // Get title from game file
3033 const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
3034 system->GetContentProvider()};
3035 const auto control = pm.GetControlMetadata();
3036 const auto loader =
3037 Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read));
3038 game_title = fmt::format("{:016X}", program_id);
3039 if (control.first != nullptr) {
3040 game_title = control.first->GetApplicationName();
3041 } else {
3042 loader->ReadTitle(game_title);
3043 }
3044 // Delete illegal characters from title
3045 const std::string illegal_chars = "<>:\"/\\|?*.";
3046 for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) {
3047 if (illegal_chars.find(*it) != std::string::npos) {
3048 game_title.erase(it.base() - 1);
3049 }
3050 }
3051 qt_game_title = QString::fromStdString(game_title);
3052 // Get icon from game file
3053 std::vector<u8> icon_image_file{};
3054 if (control.second != nullptr) {
3055 icon_image_file = control.second->ReadAllBytes();
3056 } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
3057 LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
3058 }
3059 QImage icon_data =
3060 QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
3061 if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
3062 if (!SaveIconToFile(out_icon_path, icon_data)) {
3063 LOG_ERROR(Frontend, "Could not write icon to file");
3064 }
3065 }
2977 } else { 3066 } else {
2978 LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string()); 3067 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
2979 } 3068 qt_game_title);
2980#elif defined(WIN32) 3069 LOG_ERROR(Frontend, "Invalid shortcut target");
2981 if (!SaveIconToFile(icon_path.string(), icon_data)) {
2982 LOG_ERROR(Frontend, "Could not write icon to file");
2983 return; 3070 return;
2984 } 3071 }
3072#if defined(__linux__)
3073 // Special case for AppImages
3074 // Warn once if we are making a shortcut to a volatile AppImage
3075 const std::string appimage_ending =
3076 std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage");
3077 if (yuzu_command.string().ends_with(appimage_ending) &&
3078 !UISettings::values.shortcut_already_warned) {
3079 if (GMainWindow::CreateShortcutMessagesGUI(
3080 this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, qt_game_title)) {
3081 return;
3082 }
3083 UISettings::values.shortcut_already_warned = true;
3084 }
2985#endif // __linux__ 3085#endif // __linux__
2986 3086 // Create shortcut
2987#ifdef _WIN32 3087 std::string arguments = fmt::format("-g \"{:s}\"", game_path);
2988 // Replace characters that are illegal in Windows filenames by a dash 3088 if (GMainWindow::CreateShortcutMessagesGUI(
2989 const std::string illegal_chars = "<>:\"/\\|?*"; 3089 this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qt_game_title)) {
2990 for (char c : illegal_chars) { 3090 arguments = "-f " + arguments;
2991 std::replace(title.begin(), title.end(), c, '_');
2992 } 3091 }
2993 const std::filesystem::path shortcut_path = target_directory / (title + ".lnk").c_str(); 3092 const std::string comment = fmt::format("Start {:s} with the yuzu Emulator", game_title);
2994#endif
2995
2996 const std::string comment =
2997 tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(title)).toStdString();
2998 const std::string arguments = fmt::format("-g \"{:s}\"", game_path);
2999 const std::string categories = "Game;Emulator;Qt;"; 3093 const std::string categories = "Game;Emulator;Qt;";
3000 const std::string keywords = "Switch;Nintendo;"; 3094 const std::string keywords = "Switch;Nintendo;";
3001 3095
3002 if (!CreateShortcut(shortcut_path.string(), title, comment, icon_path.string(), 3096 if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, yuzu_command,
3003 yuzu_command.string(), arguments, categories, keywords)) { 3097 arguments, categories, keywords, game_title)) {
3004 QMessageBox::critical(this, tr("Create Shortcut"), 3098 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS,
3005 tr("Failed to create a shortcut at %1") 3099 qt_game_title);
3006 .arg(QString::fromStdString(shortcut_path.string())));
3007 return; 3100 return;
3008 } 3101 }
3009 3102 GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
3010 LOG_INFO(Frontend, "Wrote a shortcut to {}", shortcut_path.string()); 3103 qt_game_title);
3011 QMessageBox::information(
3012 this, tr("Create Shortcut"),
3013 tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title)));
3014} 3104}
3015 3105
3016void GMainWindow::OnGameListOpenDirectory(const QString& directory) { 3106void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
@@ -4005,66 +4095,6 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
4005 } 4095 }
4006} 4096}
4007 4097
4008bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::string& title,
4009 const std::string& comment, const std::string& icon_path,
4010 const std::string& command, const std::string& arguments,
4011 const std::string& categories, const std::string& keywords) {
4012#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
4013 // This desktop file template was writing referencing
4014 // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html
4015 std::string shortcut_contents{};
4016 shortcut_contents.append("[Desktop Entry]\n");
4017 shortcut_contents.append("Type=Application\n");
4018 shortcut_contents.append("Version=1.0\n");
4019 shortcut_contents.append(fmt::format("Name={:s}\n", title));
4020 shortcut_contents.append(fmt::format("Comment={:s}\n", comment));
4021 shortcut_contents.append(fmt::format("Icon={:s}\n", icon_path));
4022 shortcut_contents.append(fmt::format("TryExec={:s}\n", command));
4023 shortcut_contents.append(fmt::format("Exec={:s} {:s}\n", command, arguments));
4024 shortcut_contents.append(fmt::format("Categories={:s}\n", categories));
4025 shortcut_contents.append(fmt::format("Keywords={:s}\n", keywords));
4026
4027 std::ofstream shortcut_stream(shortcut_path);
4028 if (!shortcut_stream.is_open()) {
4029 LOG_WARNING(Common, "Failed to create file {:s}", shortcut_path);
4030 return false;
4031 }
4032 shortcut_stream << shortcut_contents;
4033 shortcut_stream.close();
4034
4035 return true;
4036#elif defined(WIN32)
4037 IShellLinkW* shell_link;
4038 auto hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
4039 (void**)&shell_link);
4040 if (FAILED(hres)) {
4041 return false;
4042 }
4043 shell_link->SetPath(
4044 Common::UTF8ToUTF16W(command).data()); // Path to the object we are referring to
4045 shell_link->SetArguments(Common::UTF8ToUTF16W(arguments).data());
4046 shell_link->SetDescription(Common::UTF8ToUTF16W(comment).data());
4047 shell_link->SetIconLocation(Common::UTF8ToUTF16W(icon_path).data(), 0);
4048
4049 IPersistFile* persist_file;
4050 hres = shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file);
4051 if (FAILED(hres)) {
4052 return false;
4053 }
4054
4055 hres = persist_file->Save(Common::UTF8ToUTF16W(shortcut_path).data(), TRUE);
4056 if (FAILED(hres)) {
4057 return false;
4058 }
4059
4060 persist_file->Release();
4061 shell_link->Release();
4062
4063 return true;
4064#endif
4065 return false;
4066}
4067
4068void GMainWindow::OnLoadAmiibo() { 4098void GMainWindow::OnLoadAmiibo() {
4069 if (emu_thread == nullptr || !emu_thread->IsRunning()) { 4099 if (emu_thread == nullptr || !emu_thread->IsRunning()) {
4070 return; 4100 return;
@@ -4103,7 +4133,6 @@ void GMainWindow::OnLoadAmiibo() {
4103bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text, 4133bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text,
4104 QMessageBox::StandardButtons buttons, 4134 QMessageBox::StandardButtons buttons,
4105 QMessageBox::StandardButton defaultButton) { 4135 QMessageBox::StandardButton defaultButton) {
4106
4107 QMessageBox* box_dialog = new QMessageBox(parent); 4136 QMessageBox* box_dialog = new QMessageBox(parent);
4108 box_dialog->setWindowTitle(title); 4137 box_dialog->setWindowTitle(title);
4109 box_dialog->setText(text); 4138 box_dialog->setText(text);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index f9c6efe4f..f67c4cfda 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -6,6 +6,7 @@
6#include <memory> 6#include <memory>
7#include <optional> 7#include <optional>
8 8
9#include <filesystem>
9#include <QMainWindow> 10#include <QMainWindow>
10#include <QMessageBox> 11#include <QMessageBox>
11#include <QPushButton> 12#include <QPushButton>
@@ -174,6 +175,13 @@ class GMainWindow : public QMainWindow {
174 UI_EMU_STOPPING, 175 UI_EMU_STOPPING,
175 }; 176 };
176 177
178 enum {
179 CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES,
180 CREATE_SHORTCUT_MSGBOX_SUCCESS,
181 CREATE_SHORTCUT_MSGBOX_ERROR,
182 CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING,
183 };
184
177public: 185public:
178 void filterBarSetChecked(bool state); 186 void filterBarSetChecked(bool state);
179 void UpdateUITheme(); 187 void UpdateUITheme();
@@ -456,11 +464,14 @@ private:
456 bool ConfirmShutdownGame(); 464 bool ConfirmShutdownGame();
457 465
458 QString GetTasStateDescription() const; 466 QString GetTasStateDescription() const;
459 bool CreateShortcut(const std::string& shortcut_path, const std::string& title, 467 bool CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title);
460 const std::string& comment, const std::string& icon_path, 468 bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
461 const std::string& command, const std::string& arguments, 469 std::filesystem::path& out_icon_path);
462 const std::string& categories, const std::string& keywords); 470 bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment,
463 471 const std::filesystem::path& icon_path,
472 const std::filesystem::path& command, const std::string& arguments,
473 const std::string& categories, const std::string& keywords,
474 const std::string& name);
464 /** 475 /**
465 * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog 476 * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog
466 * The only difference is that it returns a boolean. 477 * The only difference is that it returns a boolean.
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 77d992c54..3485a6347 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -109,9 +109,13 @@ struct Values {
109 Settings::Specialization::Default, 109 Settings::Specialization::Default,
110 true, 110 true,
111 true}; 111 true};
112 Setting<bool> mute_when_in_background{ 112 Setting<bool> mute_when_in_background{linkage,
113 linkage, false, "muteWhenInBackground", Category::Audio, Settings::Specialization::Default, 113 false,
114 true, true}; 114 "muteWhenInBackground",
115 Category::UiAudio,
116 Settings::Specialization::Default,
117 true,
118 true};
115 Setting<bool> hide_mouse{ 119 Setting<bool> hide_mouse{
116 linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default, 120 linkage, true, "hideInactiveMouse", Category::UiGeneral, Settings::Specialization::Default,
117 true, true}; 121 true, true};
diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp
index f2854c8ec..7b2a47496 100644
--- a/src/yuzu/util/util.cpp
+++ b/src/yuzu/util/util.cpp
@@ -42,7 +42,7 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) {
42 return circle_pixmap; 42 return circle_pixmap;
43} 43}
44 44
45bool SaveIconToFile(const std::string_view path, const QImage& image) { 45bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image) {
46#if defined(WIN32) 46#if defined(WIN32)
47#pragma pack(push, 2) 47#pragma pack(push, 2)
48 struct IconDir { 48 struct IconDir {
@@ -73,7 +73,7 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) {
73 .id_count = static_cast<WORD>(scale_sizes.size()), 73 .id_count = static_cast<WORD>(scale_sizes.size()),
74 }; 74 };
75 75
76 Common::FS::IOFile icon_file(path, Common::FS::FileAccessMode::Write, 76 Common::FS::IOFile icon_file(icon_path.string(), Common::FS::FileAccessMode::Write,
77 Common::FS::FileType::BinaryFile); 77 Common::FS::FileType::BinaryFile);
78 if (!icon_file.IsOpen()) { 78 if (!icon_file.IsOpen()) {
79 return false; 79 return false;
@@ -135,6 +135,14 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) {
135 icon_file.Close(); 135 icon_file.Close();
136 136
137 return true; 137 return true;
138#elif defined(__linux__) || defined(__FreeBSD__)
139 // Convert and write the icon as a PNG
140 if (!image.save(QString::fromStdString(icon_path.string()))) {
141 LOG_ERROR(Frontend, "Could not write icon as PNG to file");
142 } else {
143 LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string());
144 }
145 return true;
138#else 146#else
139 return false; 147 return false;
140#endif 148#endif
diff --git a/src/yuzu/util/util.h b/src/yuzu/util/util.h
index 09c14ce3f..4094cf6c2 100644
--- a/src/yuzu/util/util.h
+++ b/src/yuzu/util/util.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <filesystem>
6#include <QFont> 7#include <QFont>
7#include <QString> 8#include <QString>
8 9
@@ -25,4 +26,4 @@
25 * @param image The image to save 26 * @param image The image to save
26 * @return bool If the operation succeeded 27 * @return bool If the operation succeeded
27 */ 28 */
28[[nodiscard]] bool SaveIconToFile(const std::string_view path, const QImage& image); 29[[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image);