summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt12
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt91
-rw-r--r--src/android/app/src/main/res/layout/fragment_search.xml1
-rw-r--r--src/android/app/src/main/res/values/strings.xml2
-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/common/settings_input.cpp9
-rw-r--r--src/common/settings_input.h7
-rw-r--r--src/core/CMakeLists.txt11
-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.h15
-rw-r--r--src/core/hid/input_interpreter.cpp7
-rw-r--r--src/core/hle/service/am/am.cpp91
-rw-r--r--src/core/hle/service/am/am.h3
-rw-r--r--src/core/hle/service/am/applets/applet_controller.h2
-rw-r--r--src/core/hle/service/btm/btm.cpp56
-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.cpp22
-rw-r--r--src/core/hle/service/hid/controllers/npad.h79
-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.cpp551
-rw-r--r--src/core/hle/service/hid/hid_system_server.h63
-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/ldn/ldn.cpp10
-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/set/set_sys.cpp30
-rw-r--r--src/core/hle/service/set/set_sys.h12
-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.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp4
-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/shader_recompiler/profile.h1
-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_pipeline_cache.cpp24
-rw-r--r--src/video_core/renderer_vulkan/vk_query_cache.cpp13
-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/video_core/vulkan_common/vulkan_device.cpp6
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h11
-rw-r--r--src/yuzu/CMakeLists.txt51
-rw-r--r--src/yuzu/applets/qt_controller.cpp1
-rw-r--r--src/yuzu/configuration/config.cpp1
-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/configuration/shared_translation.cpp517
-rw-r--r--src/yuzu/game_list.cpp6
-rw-r--r--src/yuzu/main.cpp466
-rw-r--r--src/yuzu/main.h22
-rw-r--r--src/yuzu/main.ui22
-rw-r--r--src/yuzu/util/util.cpp15
-rw-r--r--src/yuzu/util/util.h3
107 files changed, 5554 insertions, 4027 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
index b3b3fc209..6aba69dbe 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt
@@ -73,7 +73,7 @@ abstract class SettingsItem(
R.string.frame_limit_slider,
R.string.frame_limit_slider_description,
1,
- 200,
+ 400,
"%"
)
)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
index ec116ab62..6940fc757 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/InstallableFragment.kt
@@ -21,6 +21,8 @@ import org.yuzu.yuzu_emu.databinding.FragmentInstallablesBinding
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.Installable
import org.yuzu.yuzu_emu.ui.main.MainActivity
+import java.time.LocalDateTime
+import java.time.format.DateTimeFormatter
class InstallableFragment : Fragment() {
private var _binding: FragmentInstallablesBinding? = null
@@ -78,7 +80,15 @@ class InstallableFragment : Fragment() {
R.string.manage_save_data,
R.string.import_export_saves_description,
install = { mainActivity.importSaves.launch(arrayOf("application/zip")) },
- export = { mainActivity.exportSave() }
+ export = {
+ mainActivity.exportSaves.launch(
+ "yuzu saves - ${
+ LocalDateTime.now().format(
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
+ )
+ }.zip"
+ )
+ }
)
} else {
Installable(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
index de84b2adb..2fa3ab31b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
@@ -18,8 +18,8 @@ class Game(
val version: String = "",
val isHomebrew: Boolean = false
) : Parcelable {
- val keyAddedToLibraryTime get() = "${programId}_AddedToLibraryTime"
- val keyLastPlayedTime get() = "${programId}_LastPlayed"
+ val keyAddedToLibraryTime get() = "${path}_AddedToLibraryTime"
+ val keyLastPlayedTime get() = "${path}_LastPlayed"
override fun equals(other: Any?): Boolean {
if (other !is Game) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 211b7cf69..ace5dddea 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.ui.main
import android.content.Intent
import android.net.Uri
import android.os.Bundle
-import android.provider.DocumentsContract
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import android.view.WindowManager
@@ -20,7 +19,6 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
-import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
@@ -41,7 +39,6 @@ import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
-import org.yuzu.yuzu_emu.features.DocumentProvider
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
@@ -53,9 +50,6 @@ import org.yuzu.yuzu_emu.model.TaskViewModel
import org.yuzu.yuzu_emu.utils.*
import java.io.BufferedInputStream
import java.io.BufferedOutputStream
-import java.io.FileOutputStream
-import java.time.LocalDateTime
-import java.time.format.DateTimeFormatter
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
@@ -73,7 +67,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
// Get first subfolder in saves folder (should be the user folder)
val savesFolderRoot get() = File(savesFolder).listFiles()?.firstOrNull()?.canonicalPath ?: ""
- private var lastZipCreated: File? = null
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()
@@ -657,74 +650,30 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
/**
- * Zips the save files located in the given folder path and creates a new zip file with the current date and time.
- * @return true if the zip file is successfully created, false otherwise.
- */
- private fun zipSave(): Boolean {
- try {
- val tempFolder = File(getPublicFilesDir().canonicalPath, "temp")
- tempFolder.mkdirs()
- val saveFolder = File(savesFolderRoot)
- val outputZipFile = File(
- tempFolder,
- "yuzu saves - ${
- LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
- }.zip"
- )
- outputZipFile.createNewFile()
- val result = FileUtil.zipFromInternalStorage(
- saveFolder,
- savesFolderRoot,
- BufferedOutputStream(FileOutputStream(outputZipFile))
- )
- if (result == TaskState.Failed) {
- return false
- }
- lastZipCreated = outputZipFile
- } catch (e: Exception) {
- return false
- }
- return true
- }
-
- /**
* Exports the save file located in the given folder path by creating a zip file and sharing it via intent.
*/
- fun exportSave() {
- CoroutineScope(Dispatchers.IO).launch {
- val wasZipCreated = zipSave()
- val lastZipFile = lastZipCreated
- if (!wasZipCreated || lastZipFile == null) {
- withContext(Dispatchers.Main) {
- Toast.makeText(
- this@MainActivity,
- getString(R.string.export_save_failed),
- Toast.LENGTH_LONG
- ).show()
- }
- return@launch
- }
+ val exportSaves = registerForActivityResult(
+ ActivityResultContracts.CreateDocument("application/zip")
+ ) { result ->
+ if (result == null) {
+ return@registerForActivityResult
+ }
- withContext(Dispatchers.Main) {
- val file = DocumentFile.fromSingleUri(
- this@MainActivity,
- DocumentsContract.buildDocumentUri(
- DocumentProvider.AUTHORITY,
- "${DocumentProvider.ROOT_ID}/temp/${lastZipFile.name}"
- )
- )!!
- val intent = Intent(Intent.ACTION_SEND)
- .setDataAndType(file.uri, "application/zip")
- .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- .putExtra(Intent.EXTRA_STREAM, file.uri)
- startForResultExportSave.launch(
- Intent.createChooser(
- intent,
- getString(R.string.share_save_file)
- )
- )
+ IndeterminateProgressDialogFragment.newInstance(
+ this,
+ R.string.save_files_exporting,
+ false
+ ) {
+ val zipResult = FileUtil.zipFromInternalStorage(
+ File(savesFolderRoot),
+ savesFolderRoot,
+ BufferedOutputStream(contentResolver.openOutputStream(result))
+ )
+ return@newInstance when (zipResult) {
+ TaskState.Completed -> getString(R.string.export_success)
+ TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
}
- }
+ }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
}
private val startForResultExportSave =
diff --git a/src/android/app/src/main/res/layout/fragment_search.xml b/src/android/app/src/main/res/layout/fragment_search.xml
index b8d54d947..efdfd7047 100644
--- a/src/android/app/src/main/res/layout/fragment_search.xml
+++ b/src/android/app/src/main/res/layout/fragment_search.xml
@@ -127,6 +127,7 @@
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingVertical="4dp"
+ app:checkedChip="@id/chip_recently_played"
app:chipSpacingHorizontal="12dp"
app:singleLine="true"
app:singleSelection="true">
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 98c3f20f8..471af8795 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -91,6 +91,7 @@
<string name="manage_save_data">Manage save data</string>
<string name="manage_save_data_description">Save data found. Please select an option below.</string>
<string name="import_export_saves_description">Import or export save files</string>
+ <string name="save_files_exporting">Exporting save files…</string>
<string name="save_file_imported_success">Imported successfully</string>
<string name="save_file_invalid_zip_structure">Invalid save directory structure</string>
<string name="save_file_invalid_zip_structure_description">The first subfolder name must be the title ID of the game.</string>
@@ -256,6 +257,7 @@
<string name="cancelling">Cancelling</string>
<string name="install">Install</string>
<string name="delete">Delete</string>
+ <string name="export_success">Exported successfully</string>
<!-- GPU driver installation -->
<string name="select_gpu_driver">Select GPU driver</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) {
}
bool IsValidStreamCounts(u32 total_stream_count, u32 stereo_stream_count) {
- return total_stream_count > 0 && stereo_stream_count > 0 &&
+ return total_stream_count > 0 && static_cast<s32>(stereo_stream_count) >= 0 &&
stereo_stream_count <= total_stream_count && IsValidChannelCount(total_stream_count);
}
} // 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
auto* header_p{reinterpret_cast<const OpusPacketHeader*>(input_data.data())};
OpusPacketHeader header{ReverseHeader(*header_p)};
- LOG_ERROR(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
+ LOG_TRACE(Service_Audio, "header size 0x{:X} input data size 0x{:X} in_data size 0x{:X}",
header.size, input_data.size_bytes(), in_data.size_bytes());
R_UNLESS(in_data.size_bytes() >= header.size &&
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 @@
namespace Settings {
namespace NativeButton {
const std::array<const char*, NumButtons> mapping = {{
- "button_a", "button_b", "button_x", "button_y", "button_lstick",
- "button_rstick", "button_l", "button_r", "button_zl", "button_zr",
- "button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
- "button_ddown", "button_sl", "button_sr", "button_home", "button_screenshot",
+ "button_a", "button_b", "button_x", "button_y", "button_lstick",
+ "button_rstick", "button_l", "button_r", "button_zl", "button_zr",
+ "button_plus", "button_minus", "button_dleft", "button_dup", "button_dright",
+ "button_ddown", "button_slleft", "button_srleft", "button_home", "button_screenshot",
+ "button_slright", "button_srright",
}};
}
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 {
DRight,
DDown,
- SL,
- SR,
+ SLLeft,
+ SRLeft,
Home,
Screenshot,
+ SLRight,
+ SRRight,
+
NumButtons,
};
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
hle/service/grc/grc.h
hle/service/hid/hid.cpp
hle/service/hid/hid.h
+ hle/service/hid/hid_debug_server.cpp
+ hle/service/hid/hid_debug_server.h
+ hle/service/hid/hid_firmware_settings.cpp
+ hle/service/hid/hid_firmware_settings.h
+ hle/service/hid/hid_server.cpp
+ hle/service/hid/hid_server.h
+ hle/service/hid/hid_system_server.cpp
+ hle/service/hid/hid_system_server.h
hle/service/hid/hidbus.cpp
hle/service/hid/hidbus.h
hle/service/hid/irs.cpp
hle/service/hid/irs.h
hle/service/hid/irs_ring_lifo.h
+ hle/service/hid/resource_manager.cpp
+ hle/service/hid/resource_manager.h
hle/service/hid/ring_lifo.h
hle/service/hid/xcd.cpp
hle/service/hid/xcd.h
@@ -715,6 +725,7 @@ add_library(core STATIC
hle/service/nvnflinger/producer_listener.h
hle/service/nvnflinger/status.h
hle/service/nvnflinger/ui/fence.h
+ hle/service/nvnflinger/ui/graphic_buffer.cpp
hle/service/nvnflinger/ui/graphic_buffer.h
hle/service/nvnflinger/window.h
hle/service/olsc/olsc.cpp
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>;
using ConsoleMotionValues = ConsoleMotionInfo;
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
-struct TouchFinger {
- u64 last_touch{};
- Common::Point<float> position{};
- u32 id{};
- TouchAttribute attribute{};
- bool pressed{};
-};
-
// Contains all motion related data that is used on the services
struct ConsoleMotion {
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() {
tas_button_params[Settings::NativeButton::DUp].Set("button", 13);
tas_button_params[Settings::NativeButton::DRight].Set("button", 14);
tas_button_params[Settings::NativeButton::DDown].Set("button", 15);
- tas_button_params[Settings::NativeButton::SL].Set("button", 16);
- tas_button_params[Settings::NativeButton::SR].Set("button", 17);
+ tas_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
+ tas_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
tas_button_params[Settings::NativeButton::Home].Set("button", 18);
tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
+ tas_button_params[Settings::NativeButton::SLRight].Set("button", 20);
+ tas_button_params[Settings::NativeButton::SRRight].Set("button", 21);
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
@@ -296,10 +298,12 @@ void EmulatedController::LoadVirtualGamepadParams() {
virtual_button_params[Settings::NativeButton::DUp].Set("button", 13);
virtual_button_params[Settings::NativeButton::DRight].Set("button", 14);
virtual_button_params[Settings::NativeButton::DDown].Set("button", 15);
- virtual_button_params[Settings::NativeButton::SL].Set("button", 16);
- virtual_button_params[Settings::NativeButton::SR].Set("button", 17);
+ virtual_button_params[Settings::NativeButton::SLLeft].Set("button", 16);
+ virtual_button_params[Settings::NativeButton::SRLeft].Set("button", 17);
virtual_button_params[Settings::NativeButton::Home].Set("button", 18);
virtual_button_params[Settings::NativeButton::Screenshot].Set("button", 19);
+ virtual_button_params[Settings::NativeButton::SLRight].Set("button", 20);
+ virtual_button_params[Settings::NativeButton::SRRight].Set("button", 21);
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0);
virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1);
@@ -867,12 +871,16 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
controller.npad_button_state.down.Assign(current_status.value);
controller.debug_pad_button_state.d_down.Assign(current_status.value);
break;
- case Settings::NativeButton::SL:
+ case Settings::NativeButton::SLLeft:
controller.npad_button_state.left_sl.Assign(current_status.value);
+ break;
+ case Settings::NativeButton::SLRight:
controller.npad_button_state.right_sl.Assign(current_status.value);
break;
- case Settings::NativeButton::SR:
+ case Settings::NativeButton::SRLeft:
controller.npad_button_state.left_sr.Assign(current_status.value);
+ break;
+ case Settings::NativeButton::SRRight:
controller.npad_button_state.right_sr.Assign(current_status.value);
break;
case Settings::NativeButton::Home:
@@ -1890,12 +1898,16 @@ NpadButton EmulatedController::GetTurboButtonMask() const {
case Settings::NativeButton::DDown:
button_mask.down.Assign(1);
break;
- case Settings::NativeButton::SL:
+ case Settings::NativeButton::SLLeft:
button_mask.left_sl.Assign(1);
+ break;
+ case Settings::NativeButton::SLRight:
button_mask.right_sl.Assign(1);
break;
- case Settings::NativeButton::SR:
+ case Settings::NativeButton::SRLeft:
button_mask.left_sr.Assign(1);
+ break;
+ case Settings::NativeButton::SRRight:
button_mask.right_sr.Assign(1);
break;
default:
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index 7ba75a50c..70fcc6b69 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -218,6 +218,13 @@ enum class NpadIdType : u32 {
Invalid = 0xFFFFFFFF,
};
+enum class NpadInterfaceType : u8 {
+ Bluetooth = 1,
+ Rail = 2,
+ Usb = 3,
+ Embedded = 4,
+};
+
// This is nn::hid::NpadStyleIndex
enum class NpadStyleIndex : u8 {
None = 0,
@@ -356,6 +363,14 @@ struct TouchState {
};
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
+struct TouchFinger {
+ u64 last_touch{};
+ Common::Point<float> position{};
+ u32 id{};
+ TouchAttribute attribute{};
+ bool pressed{};
+};
+
// This is nn::hid::TouchScreenConfigurationForNx
struct TouchScreenConfigurationForNx {
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 @@
#include "core/hid/hid_types.h"
#include "core/hid/input_interpreter.h"
#include "core/hle/service/hid/controllers/npad.h"
-#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/hid/hid_server.h"
+#include "core/hle/service/hid/resource_manager.h"
#include "core/hle/service/sm/sm.h"
InputInterpreter::InputInterpreter(Core::System& system)
: npad{system.ServiceManager()
- .GetService<Service::HID::Hid>("hid")
- ->GetAppletResource()
+ .GetService<Service::HID::IHidServer>("hid")
+ ->GetResourceManager()
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
ResetButtonStates();
}
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index cc643ea09..a266d7c21 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -13,6 +13,7 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/savedata_factory.h"
+#include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/result.h"
@@ -21,6 +22,7 @@
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applet_cabinet.h"
+#include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
#include "core/hle/service/am/applets/applet_profile_select.h"
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
@@ -35,6 +37,7 @@
#include "core/hle/service/caps/caps_su.h"
#include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
@@ -73,7 +76,7 @@ IWindowController::IWindowController(Core::System& system_)
static const FunctionInfo functions[] = {
{0, nullptr, "CreateWindow"},
{1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
- {2, nullptr, "GetAppletResourceUserIdOfCallerApplet"},
+ {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"},
{10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
{11, nullptr, "ReleaseForegroundRights"},
{12, nullptr, "RejectToChangeIntoBackground"},
@@ -97,6 +100,16 @@ void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) {
rb.Push<u64>(process_id);
}
+void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) {
+ const u64 process_id = 0;
+
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push<u64>(process_id);
+}
+
void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -1565,7 +1578,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
{6, nullptr, "GetPopInteractiveInDataEvent"},
{10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
{11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
- {12, nullptr, "GetMainAppletIdentityInfo"},
+ {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
{13, nullptr, "CanUseApplicationCore"},
{14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
{15, nullptr, "GetMainAppletApplicationControlProperty"},
@@ -1609,6 +1622,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
case Applets::AppletId::SoftwareKeyboard:
PushInShowSoftwareKeyboard();
break;
+ case Applets::AppletId::Controller:
+ PushInShowController();
+ break;
default:
break;
}
@@ -1666,13 +1682,33 @@ void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
rb.PushRaw(applet_info);
}
-void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
+void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
struct AppletIdentityInfo {
Applets::AppletId applet_id;
INSERT_PADDING_BYTES(0x4);
u64 application_id;
};
+ static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
+
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+
+ const AppletIdentityInfo applet_info{
+ .applet_id = Applets::AppletId::QLaunch,
+ .application_id = 0x0100000000001000ull,
+ };
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(applet_info);
+}
+void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
+ struct AppletIdentityInfo {
+ Applets::AppletId applet_id;
+ INSERT_PADDING_BYTES(0x4);
+ u64 application_id;
+ };
+ static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
LOG_WARNING(Service_AM, "(STUBBED) called");
const AppletIdentityInfo applet_info{
@@ -1737,6 +1773,55 @@ void ILibraryAppletSelfAccessor::PushInShowAlbum() {
queue_data.emplace_back(std::move(settings_data));
}
+void ILibraryAppletSelfAccessor::PushInShowController() {
+ const Applets::CommonArguments common_args = {
+ .arguments_version = Applets::CommonArgumentVersion::Version3,
+ .size = Applets::CommonArgumentSize::Version3,
+ .library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8),
+ .theme_color = Applets::ThemeColor::BasicBlack,
+ .play_startup_sound = true,
+ .system_tick = system.CoreTiming().GetClockTicks(),
+ };
+
+ Applets::ControllerSupportArgNew user_args = {
+ .header = {.player_count_min = 1,
+ .player_count_max = 4,
+ .enable_take_over_connection = true,
+ .enable_left_justify = false,
+ .enable_permit_joy_dual = true,
+ .enable_single_mode = false,
+ .enable_identification_color = false},
+ .identification_colors = {},
+ .enable_explain_text = false,
+ .explain_text = {},
+ };
+
+ Applets::ControllerSupportArgPrivate private_args = {
+ .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate),
+ .arg_size = sizeof(Applets::ControllerSupportArgNew),
+ .is_home_menu = true,
+ .flag_1 = true,
+ .mode = Applets::ControllerSupportMode::ShowControllerSupport,
+ .caller = Applets::ControllerSupportCaller::
+ Application, // switchbrew: Always zero except with
+ // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
+ // which sets this to the input param
+ .style_set = Core::HID::NpadStyleSet::None,
+ .joy_hold_type = 0,
+ };
+ std::vector<u8> common_args_data(sizeof(common_args));
+ std::vector<u8> private_args_data(sizeof(private_args));
+ std::vector<u8> user_args_data(sizeof(user_args));
+
+ std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
+ std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
+ std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
+
+ queue_data.emplace_back(std::move(common_args_data));
+ queue_data.emplace_back(std::move(private_args_data));
+ queue_data.emplace_back(std::move(user_args_data));
+}
+
void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
const Applets::CommonArguments arguments{
.arguments_version = Applets::CommonArgumentVersion::Version3,
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 8f8cb8a9e..905a71b9f 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -87,6 +87,7 @@ public:
private:
void GetAppletResourceUserId(HLERequestContext& ctx);
+ void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
void AcquireForegroundRights(HLERequestContext& ctx);
};
@@ -345,6 +346,7 @@ private:
void PopInData(HLERequestContext& ctx);
void PushOutData(HLERequestContext& ctx);
void GetLibraryAppletInfo(HLERequestContext& ctx);
+ void GetMainAppletIdentityInfo(HLERequestContext& ctx);
void ExitProcessAndReturn(HLERequestContext& ctx);
void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
void GetDesirableKeyboardLayout(HLERequestContext& ctx);
@@ -355,6 +357,7 @@ private:
void PushInShowCabinetData();
void PushInShowMiiEditData();
void PushInShowSoftwareKeyboard();
+ void PushInShowController();
std::deque<std::vector<u8>> queue_data;
};
diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h
index f6c64f633..9f839f3d7 100644
--- a/src/core/hle/service/am/applets/applet_controller.h
+++ b/src/core/hle/service/am/applets/applet_controller.h
@@ -56,7 +56,7 @@ enum class ControllerSupportResult : u32 {
struct ControllerSupportArgPrivate {
u32 arg_private_size{};
u32 arg_size{};
- bool flag_0{};
+ bool is_home_menu{};
bool flag_1{};
ControllerSupportMode mode{};
ControllerSupportCaller caller{};
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 8069f75b7..c65e32489 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -127,7 +127,7 @@ public:
private:
void GetCore(HLERequestContext& ctx) {
- LOG_DEBUG(Service_BTM, "called");
+ LOG_WARNING(Service_BTM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
@@ -263,13 +263,13 @@ public:
explicit IBtmSystemCore(Core::System& system_) : ServiceFramework{system_, "IBtmSystemCore"} {
// clang-format off
static const FunctionInfo functions[] = {
- {0, nullptr, "StartGamepadPairing"},
- {1, nullptr, "CancelGamepadPairing"},
+ {0, &IBtmSystemCore::StartGamepadPairing, "StartGamepadPairing"},
+ {1, &IBtmSystemCore::CancelGamepadPairing, "CancelGamepadPairing"},
{2, nullptr, "ClearGamepadPairingDatabase"},
{3, nullptr, "GetPairedGamepadCount"},
{4, nullptr, "EnableRadio"},
{5, nullptr, "DisableRadio"},
- {6, nullptr, "GetRadioOnOff"},
+ {6, &IBtmSystemCore::IsRadioEnabled, "IsRadioEnabled"},
{7, nullptr, "AcquireRadioEvent"},
{8, nullptr, "AcquireGamepadPairingEvent"},
{9, nullptr, "IsGamepadPairingStarted"},
@@ -280,18 +280,58 @@ public:
{14, nullptr, "AcquireAudioDeviceConnectionEvent"},
{15, nullptr, "ConnectAudioDevice"},
{16, nullptr, "IsConnectingAudioDevice"},
- {17, nullptr, "GetConnectedAudioDevices"},
+ {17, &IBtmSystemCore::GetConnectedAudioDevices, "GetConnectedAudioDevices"},
{18, nullptr, "DisconnectAudioDevice"},
{19, nullptr, "AcquirePairedAudioDeviceInfoChangedEvent"},
{20, nullptr, "GetPairedAudioDevices"},
{21, nullptr, "RemoveAudioDevicePairing"},
- {22, nullptr, "RequestAudioDeviceConnectionRejection"},
- {23, nullptr, "CancelAudioDeviceConnectionRejection"}
+ {22, &IBtmSystemCore::RequestAudioDeviceConnectionRejection, "RequestAudioDeviceConnectionRejection"},
+ {23, &IBtmSystemCore::CancelAudioDeviceConnectionRejection, "CancelAudioDeviceConnectionRejection"}
};
// clang-format on
RegisterHandlers(functions);
}
+
+private:
+ void IsRadioEnabled(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_BTM, "(STUBBED) called"); // Spams a lot when controller applet is running
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(true);
+ }
+
+ void StartGamepadPairing(HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void CancelGamepadPairing(HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void CancelAudioDeviceConnectionRejection(HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void GetConnectedAudioDevices(HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push<u32>(0);
+ }
+
+ void RequestAudioDeviceConnectionRejection(HLERequestContext& ctx) {
+ LOG_WARNING(Service_BTM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
};
class BTM_SYS final : public ServiceFramework<BTM_SYS> {
@@ -308,7 +348,7 @@ public:
private:
void GetCore(HLERequestContext& ctx) {
- LOG_DEBUG(Service_BTM, "called");
+ LOG_WARNING(Service_BTM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
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 {
ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
ControllerBase::~ControllerBase() = default;
-void ControllerBase::ActivateController() {
+Result ControllerBase::Activate() {
if (is_activated) {
- return;
+ return ResultSuccess;
}
is_activated = true;
OnInit();
+ return ResultSuccess;
+}
+
+Result ControllerBase::Activate(u64 aruid) {
+ return Activate();
}
void 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 @@
#pragma once
#include "common/common_types.h"
+#include "core/hle/result.h"
namespace Core::Timing {
class CoreTiming;
@@ -31,7 +32,8 @@ public:
// When the controller is requesting a motion update for the shared memory
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {}
- void ActivateController();
+ Result Activate();
+ Result Activate(u64 aruid);
void DeactivateController();
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 21695bda2..127af2b82 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -344,6 +344,7 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
controller.device->SetPollingMode(Core::HID::EmulatedDeviceIndex::AllDevices,
Common::Input::PollingMode::Active);
}
+
SignalStyleSetChangedEvent(npad_id);
WriteEmptyEntry(controller.shared_memory);
hid_core.SetLastActiveController(npad_id);
@@ -457,12 +458,14 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) {
pad_entry.l_stick = stick_state.left;
}
- if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) {
+ if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft ||
+ controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl);
pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr);
}
- if (controller_type == Core::HID::NpadStyleIndex::JoyconRight) {
+ if (controller_type == Core::HID::NpadStyleIndex::JoyconRight ||
+ controller_type == Core::HID::NpadStyleIndex::JoyconDual) {
pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl);
pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr);
}
@@ -1724,4 +1727,19 @@ const Controller_NPad::SixaxisParameters& Controller_NPad::GetSixaxisState(
}
}
+Controller_NPad::AppletDetailedUiType Controller_NPad::GetAppletDetailedUiType(
+ Core::HID::NpadIdType npad_id) {
+
+ auto controller = GetControllerFromNpadIdType(npad_id);
+ auto shared_memory = controller.shared_memory;
+ Service::HID::Controller_NPad::AppletFooterUiType applet_footer_type =
+ shared_memory->applet_footer_type;
+
+ Controller_NPad::AppletDetailedUiType detailed_ui_type{
+ .ui_variant = 0,
+ .footer = applet_footer_type,
+ };
+ return detailed_ui_type;
+}
+
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 949e58a4c..cd93abdd1 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -78,6 +78,46 @@ public:
MaxActivationMode = 3,
};
+ // This is nn::hid::system::AppletFooterUiAttributesSet
+ struct AppletFooterUiAttributes {
+ INSERT_PADDING_BYTES(0x4);
+ };
+
+ // This is nn::hid::system::AppletFooterUiType
+ enum class AppletFooterUiType : u8 {
+ None = 0,
+ HandheldNone = 1,
+ HandheldJoyConLeftOnly = 2,
+ HandheldJoyConRightOnly = 3,
+ HandheldJoyConLeftJoyConRight = 4,
+ JoyDual = 5,
+ JoyDualLeftOnly = 6,
+ JoyDualRightOnly = 7,
+ JoyLeftHorizontal = 8,
+ JoyLeftVertical = 9,
+ JoyRightHorizontal = 10,
+ JoyRightVertical = 11,
+ SwitchProController = 12,
+ CompatibleProController = 13,
+ CompatibleJoyCon = 14,
+ LarkHvc1 = 15,
+ LarkHvc2 = 16,
+ LarkNesLeft = 17,
+ LarkNesRight = 18,
+ Lucia = 19,
+ Verification = 20,
+ Lagon = 21,
+ };
+
+ using AppletFooterUiVariant = u8;
+
+ // This is "nn::hid::system::AppletDetailedUiType".
+ struct AppletDetailedUiType {
+ AppletFooterUiVariant ui_variant;
+ INSERT_PADDING_BYTES(0x2);
+ AppletFooterUiType footer;
+ };
+ static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
// This is nn::hid::NpadCommunicationMode
enum class NpadCommunicationMode : u64 {
Mode_5ms = 0,
@@ -86,6 +126,13 @@ public:
Default = 3,
};
+ enum class NpadRevision : u32 {
+ Revision0 = 0,
+ Revision1 = 1,
+ Revision2 = 2,
+ Revision3 = 3,
+ };
+
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
@@ -196,6 +243,7 @@ public:
static Result IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
static Result VerifyValidSixAxisSensorHandle(
const Core::HID::SixAxisSensorHandle& device_handle);
+ AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
private:
static constexpr std::size_t NPAD_COUNT = 10;
@@ -353,37 +401,6 @@ private:
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
"NfcXcdDeviceHandleStateImpl is an invalid size");
- // This is nn::hid::system::AppletFooterUiAttributesSet
- struct AppletFooterUiAttributes {
- INSERT_PADDING_BYTES(0x4);
- };
-
- // This is nn::hid::system::AppletFooterUiType
- enum class AppletFooterUiType : u8 {
- None = 0,
- HandheldNone = 1,
- HandheldJoyConLeftOnly = 2,
- HandheldJoyConRightOnly = 3,
- HandheldJoyConLeftJoyConRight = 4,
- JoyDual = 5,
- JoyDualLeftOnly = 6,
- JoyDualRightOnly = 7,
- JoyLeftHorizontal = 8,
- JoyLeftVertical = 9,
- JoyRightHorizontal = 10,
- JoyRightVertical = 11,
- SwitchProController = 12,
- CompatibleProController = 13,
- CompatibleJoyCon = 14,
- LarkHvc1 = 15,
- LarkHvc2 = 16,
- LarkNesLeft = 17,
- LarkNesRight = 18,
- Lucia = 19,
- Verification = 20,
- Lagon = 21,
- };
-
// This is nn::hid::NpadLarkType
enum class NpadLarkType : u32 {
Invalid,
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) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
- ActivateController();
+ Activate();
return ResultSuccess;
}
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 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <array>
-#include "common/common_types.h"
-#include "common/logging/log.h"
-#include "common/settings.h"
-#include "core/core.h"
-#include "core/core_timing.h"
-#include "core/hid/hid_core.h"
-#include "core/hle/kernel/k_readable_event.h"
-#include "core/hle/kernel/k_shared_memory.h"
-#include "core/hle/kernel/k_transfer_memory.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/hid/hid_debug_server.h"
+#include "core/hle/service/hid/hid_firmware_settings.h"
+#include "core/hle/service/hid/hid_server.h"
+#include "core/hle/service/hid/hid_system_server.h"
#include "core/hle/service/hid/hidbus.h"
#include "core/hle/service/hid/irs.h"
+#include "core/hle/service/hid/resource_manager.h"
#include "core/hle/service/hid/xcd.h"
-#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
-#include "core/memory.h"
-
-#include "core/hle/service/hid/controllers/console_sixaxis.h"
-#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/controllers/debug_pad.h"
-#include "core/hle/service/hid/controllers/gesture.h"
-#include "core/hle/service/hid/controllers/keyboard.h"
-#include "core/hle/service/hid/controllers/mouse.h"
-#include "core/hle/service/hid/controllers/npad.h"
-#include "core/hle/service/hid/controllers/palma.h"
-#include "core/hle/service/hid/controllers/stubbed.h"
-#include "core/hle/service/hid/controllers/touchscreen.h"
-#include "core/hle/service/hid/controllers/xpad.h"
namespace Service::HID {
-// Updating period for each HID device.
-// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
-// Correct npad_update_ns is 4ms this is overclocked to lower input lag
-constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
-constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
-constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
-constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
-
-IAppletResource::IAppletResource(Core::System& system_,
- KernelHelpers::ServiceContext& service_context_)
- : ServiceFramework{system_, "IAppletResource"}, service_context{service_context_} {
- static const FunctionInfo functions[] = {
- {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
- };
- RegisterHandlers(functions);
- u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
- MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
- MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
- MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
- MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
- MakeController<Controller_XPad>(HidController::XPad, shared_memory);
- MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
- MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
- MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
- MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
- MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
- MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
- MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
- MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
- MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory);
- MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
-
- // Homebrew doesn't try to activate some controllers, so we activate them by default
- GetController<Controller_NPad>(HidController::NPad).ActivateController();
- GetController<Controller_Touchscreen>(HidController::Touchscreen).ActivateController();
-
- GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
- GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
- GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
- GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
- GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
- GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00);
-
- // Register update callbacks
- npad_update_event = Core::Timing::CreateEvent(
- "HID::UpdatePadCallback",
- [this](std::uintptr_t user_data, s64 time,
- std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
- const auto guard = LockService();
- UpdateNpad(user_data, ns_late);
- return std::nullopt;
- });
- default_update_event = Core::Timing::CreateEvent(
- "HID::UpdateDefaultCallback",
- [this](std::uintptr_t user_data, s64 time,
- std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
- const auto guard = LockService();
- UpdateControllers(user_data, ns_late);
- return std::nullopt;
- });
- mouse_keyboard_update_event = Core::Timing::CreateEvent(
- "HID::UpdateMouseKeyboardCallback",
- [this](std::uintptr_t user_data, s64 time,
- std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
- const auto guard = LockService();
- UpdateMouseKeyboard(user_data, ns_late);
- return std::nullopt;
- });
- motion_update_event = Core::Timing::CreateEvent(
- "HID::UpdateMotionCallback",
- [this](std::uintptr_t user_data, s64 time,
- std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
- const auto guard = LockService();
- UpdateMotion(user_data, ns_late);
- return std::nullopt;
- });
-
- system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
- system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
- default_update_event);
- system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
- mouse_keyboard_update_event);
- system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
- motion_update_event);
-
- system.HIDCore().ReloadInputDevices();
-}
-
-void IAppletResource::ActivateController(HidController controller) {
- controllers[static_cast<size_t>(controller)]->ActivateController();
-}
-
-void IAppletResource::DeactivateController(HidController controller) {
- controllers[static_cast<size_t>(controller)]->DeactivateController();
-}
-
-IAppletResource::~IAppletResource() {
- system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
- system.CoreTiming().UnscheduleEvent(default_update_event, 0);
- system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
- system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
-}
-
-void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
- LOG_DEBUG(Service_HID, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
-}
-
-void IAppletResource::UpdateControllers(std::uintptr_t user_data,
- std::chrono::nanoseconds ns_late) {
- auto& core_timing = system.CoreTiming();
-
- for (const auto& controller : controllers) {
- // Keyboard has it's own update event
- if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
- continue;
- }
- // Mouse has it's own update event
- if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
- continue;
- }
- // Npad has it's own update event
- if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
- continue;
- }
- controller->OnUpdate(core_timing);
- }
-}
-
-void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
- auto& core_timing = system.CoreTiming();
-
- controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
-}
-
-void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
- std::chrono::nanoseconds ns_late) {
- auto& core_timing = system.CoreTiming();
-
- controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
- controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
-}
-
-void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
- auto& core_timing = system.CoreTiming();
-
- controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
-}
-
-class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
-public:
- explicit IActiveVibrationDeviceList(Core::System& system_,
- std::shared_ptr<IAppletResource> applet_resource_)
- : ServiceFramework{system_, "IActiveVibrationDeviceList"},
- applet_resource(applet_resource_) {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
-private:
- void InitializeVibrationDevice(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
-
- if (applet_resource != nullptr) {
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .InitializeVibrationDevice(vibration_device_handle);
- }
-
- LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
- vibration_device_handle.npad_type, vibration_device_handle.npad_id,
- vibration_device_handle.device_index);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- std::shared_ptr<IAppletResource> applet_resource;
-};
-
-std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
- if (applet_resource == nullptr) {
- applet_resource = std::make_shared<IAppletResource>(system, service_context);
- }
-
- return applet_resource;
-}
-
-Hid::Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_)
- : ServiceFramework{system_, "hid"}, applet_resource{applet_resource_}, service_context{
- system_,
- service_name} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &Hid::CreateAppletResource, "CreateAppletResource"},
- {1, &Hid::ActivateDebugPad, "ActivateDebugPad"},
- {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"},
- {21, &Hid::ActivateMouse, "ActivateMouse"},
- {26, nullptr, "ActivateDebugMouse"},
- {31, &Hid::ActivateKeyboard, "ActivateKeyboard"},
- {32, &Hid::SendKeyboardLockKeyEvent, "SendKeyboardLockKeyEvent"},
- {40, nullptr, "AcquireXpadIdEventHandle"},
- {41, nullptr, "ReleaseXpadIdEventHandle"},
- {51, &Hid::ActivateXpad, "ActivateXpad"},
- {55, &Hid::GetXpadIDs, "GetXpadIds"},
- {56, nullptr, "ActivateJoyXpad"},
- {58, nullptr, "GetJoyXpadLifoHandle"},
- {59, nullptr, "GetJoyXpadIds"},
- {60, &Hid::ActivateSixAxisSensor, "ActivateSixAxisSensor"},
- {61, &Hid::DeactivateSixAxisSensor, "DeactivateSixAxisSensor"},
- {62, nullptr, "GetSixAxisSensorLifoHandle"},
- {63, nullptr, "ActivateJoySixAxisSensor"},
- {64, nullptr, "DeactivateJoySixAxisSensor"},
- {65, nullptr, "GetJoySixAxisSensorLifoHandle"},
- {66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
- {67, &Hid::StopSixAxisSensor, "StopSixAxisSensor"},
- {68, &Hid::IsSixAxisSensorFusionEnabled, "IsSixAxisSensorFusionEnabled"},
- {69, &Hid::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"},
- {70, &Hid::SetSixAxisSensorFusionParameters, "SetSixAxisSensorFusionParameters"},
- {71, &Hid::GetSixAxisSensorFusionParameters, "GetSixAxisSensorFusionParameters"},
- {72, &Hid::ResetSixAxisSensorFusionParameters, "ResetSixAxisSensorFusionParameters"},
- {73, nullptr, "SetAccelerometerParameters"},
- {74, nullptr, "GetAccelerometerParameters"},
- {75, nullptr, "ResetAccelerometerParameters"},
- {76, nullptr, "SetAccelerometerPlayMode"},
- {77, nullptr, "GetAccelerometerPlayMode"},
- {78, nullptr, "ResetAccelerometerPlayMode"},
- {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
- {80, &Hid::GetGyroscopeZeroDriftMode, "GetGyroscopeZeroDriftMode"},
- {81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"},
- {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
- {83, &Hid::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"},
- {84, &Hid::EnableSixAxisSensorUnalteredPassthrough, "EnableSixAxisSensorUnalteredPassthrough"},
- {85, &Hid::IsSixAxisSensorUnalteredPassthroughEnabled, "IsSixAxisSensorUnalteredPassthroughEnabled"},
- {86, nullptr, "StoreSixAxisSensorCalibrationParameter"},
- {87, &Hid::LoadSixAxisSensorCalibrationParameter, "LoadSixAxisSensorCalibrationParameter"},
- {88, &Hid::GetSixAxisSensorIcInformation, "GetSixAxisSensorIcInformation"},
- {89, &Hid::ResetIsSixAxisSensorDeviceNewlyAssigned, "ResetIsSixAxisSensorDeviceNewlyAssigned"},
- {91, &Hid::ActivateGesture, "ActivateGesture"},
- {100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
- {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
- {102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
- {103, &Hid::ActivateNpad, "ActivateNpad"},
- {104, &Hid::DeactivateNpad, "DeactivateNpad"},
- {106, &Hid::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
- {107, &Hid::DisconnectNpad, "DisconnectNpad"},
- {108, &Hid::GetPlayerLedPattern, "GetPlayerLedPattern"},
- {109, &Hid::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
- {120, &Hid::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
- {121, &Hid::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
- {122, &Hid::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
- {123, &Hid::SetNpadJoyAssignmentModeSingle, "SetNpadJoyAssignmentModeSingle"},
- {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
- {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
- {126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"},
- {127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"},
- {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
- {129, &Hid::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"},
- {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
- {131, &Hid::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
- {132, &Hid::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
- {133, &Hid::SetNpadJoyAssignmentModeSingleWithDestination, "SetNpadJoyAssignmentModeSingleWithDestination"},
- {134, &Hid::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
- {135, &Hid::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"},
- {136, &Hid::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"},
- {200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
- {201, &Hid::SendVibrationValue, "SendVibrationValue"},
- {202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
- {203, &Hid::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
- {204, &Hid::PermitVibration, "PermitVibration"},
- {205, &Hid::IsVibrationPermitted, "IsVibrationPermitted"},
- {206, &Hid::SendVibrationValues, "SendVibrationValues"},
- {207, &Hid::SendVibrationGcErmCommand, "SendVibrationGcErmCommand"},
- {208, &Hid::GetActualVibrationGcErmCommand, "GetActualVibrationGcErmCommand"},
- {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
- {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
- {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
- {212, nullptr, "SendVibrationValueInBool"},
- {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
- {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
- {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
- {303, &Hid::ActivateSevenSixAxisSensor, "ActivateSevenSixAxisSensor"},
- {304, &Hid::StartSevenSixAxisSensor, "StartSevenSixAxisSensor"},
- {305, &Hid::StopSevenSixAxisSensor, "StopSevenSixAxisSensor"},
- {306, &Hid::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"},
- {307, &Hid::FinalizeSevenSixAxisSensor, "FinalizeSevenSixAxisSensor"},
- {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
- {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
- {310, &Hid::ResetSevenSixAxisSensorTimestamp, "ResetSevenSixAxisSensorTimestamp"},
- {400, &Hid::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
- {401, nullptr, "EnableUsbFullKeyController"},
- {402, nullptr, "IsUsbFullKeyControllerConnected"},
- {403, nullptr, "HasBattery"},
- {404, nullptr, "HasLeftRightBattery"},
- {405, nullptr, "GetNpadInterfaceType"},
- {406, nullptr, "GetNpadLeftRightInterfaceType"},
- {407, nullptr, "GetNpadOfHighestBatteryLevel"},
- {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
- {500, &Hid::GetPalmaConnectionHandle, "GetPalmaConnectionHandle"},
- {501, &Hid::InitializePalma, "InitializePalma"},
- {502, &Hid::AcquirePalmaOperationCompleteEvent, "AcquirePalmaOperationCompleteEvent"},
- {503, &Hid::GetPalmaOperationInfo, "GetPalmaOperationInfo"},
- {504, &Hid::PlayPalmaActivity, "PlayPalmaActivity"},
- {505, &Hid::SetPalmaFrModeType, "SetPalmaFrModeType"},
- {506, &Hid::ReadPalmaStep, "ReadPalmaStep"},
- {507, &Hid::EnablePalmaStep, "EnablePalmaStep"},
- {508, &Hid::ResetPalmaStep, "ResetPalmaStep"},
- {509, &Hid::ReadPalmaApplicationSection, "ReadPalmaApplicationSection"},
- {510, &Hid::WritePalmaApplicationSection, "WritePalmaApplicationSection"},
- {511, &Hid::ReadPalmaUniqueCode, "ReadPalmaUniqueCode"},
- {512, &Hid::SetPalmaUniqueCodeInvalid, "SetPalmaUniqueCodeInvalid"},
- {513, &Hid::WritePalmaActivityEntry, "WritePalmaActivityEntry"},
- {514, &Hid::WritePalmaRgbLedPatternEntry, "WritePalmaRgbLedPatternEntry"},
- {515, &Hid::WritePalmaWaveEntry, "WritePalmaWaveEntry"},
- {516, &Hid::SetPalmaDataBaseIdentificationVersion, "SetPalmaDataBaseIdentificationVersion"},
- {517, &Hid::GetPalmaDataBaseIdentificationVersion, "GetPalmaDataBaseIdentificationVersion"},
- {518, &Hid::SuspendPalmaFeature, "SuspendPalmaFeature"},
- {519, &Hid::GetPalmaOperationResult, "GetPalmaOperationResult"},
- {520, &Hid::ReadPalmaPlayLog, "ReadPalmaPlayLog"},
- {521, &Hid::ResetPalmaPlayLog, "ResetPalmaPlayLog"},
- {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
- {523, &Hid::SetIsPalmaPairedConnectable, "SetIsPalmaPairedConnectable"},
- {524, &Hid::PairPalma, "PairPalma"},
- {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
- {526, &Hid::CancelWritePalmaWaveEntry, "CancelWritePalmaWaveEntry"},
- {527, &Hid::EnablePalmaBoostMode, "EnablePalmaBoostMode"},
- {528, &Hid::GetPalmaBluetoothAddress, "GetPalmaBluetoothAddress"},
- {529, &Hid::SetDisallowedPalmaConnection, "SetDisallowedPalmaConnection"},
- {1000, &Hid::SetNpadCommunicationMode, "SetNpadCommunicationMode"},
- {1001, &Hid::GetNpadCommunicationMode, "GetNpadCommunicationMode"},
- {1002, &Hid::SetTouchScreenConfiguration, "SetTouchScreenConfiguration"},
- {1003, &Hid::IsFirmwareUpdateNeededForNotification, "IsFirmwareUpdateNeededForNotification"},
- {2000, nullptr, "ActivateDigitizer"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-Hid::~Hid() = default;
-
-void Hid::CreateAppletResource(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- if (applet_resource == nullptr) {
- applet_resource = std::make_shared<IAppletResource>(system, service_context);
- }
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IAppletResource>(applet_resource);
-}
-
-void Hid::ActivateDebugPad(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->ActivateController(HidController::DebugPad);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ActivateTouchScreen(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->ActivateController(HidController::Touchscreen);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ActivateMouse(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->ActivateController(HidController::Mouse);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ActivateKeyboard(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->ActivateController(HidController::Keyboard);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SendKeyboardLockKeyEvent(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto flags{rp.Pop<u32>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ActivateXpad(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- u32 basic_xpad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- applet_resource->ActivateController(HidController::XPad);
-
- LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
- parameters.basic_xpad_id, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetXpadIDs(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(0);
-}
-
-void Hid::ActivateSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- u32 basic_xpad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- // This function does nothing on 10.0.0+
-
- LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}",
- parameters.basic_xpad_id, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::DeactivateSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- u32 basic_xpad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- // This function does nothing on 10.0.0+
-
- LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}",
- parameters.basic_xpad_id, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::StartSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, true);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::StopSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, false);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::IsSixAxisSensorFusionEnabled(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- bool is_enabled{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result =
- controller.IsSixAxisSensorFusionEnabled(parameters.sixaxis_handle, is_enabled);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result);
- rb.Push(is_enabled);
-}
-
-void Hid::EnableSixAxisSensorFusion(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- bool enable_sixaxis_sensor_fusion;
- INSERT_PADDING_BYTES_NOINIT(3);
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle,
- parameters.enable_sixaxis_sensor_fusion);
-
- LOG_DEBUG(Service_HID,
- "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
- "device_index={}, applet_resource_user_id={}",
- parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
- parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
- parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::SetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- Core::HID::SixAxisSensorFusionParameters sixaxis_fusion;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result =
- controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, "
- "parameter2={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1,
- parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::GetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- Core::HID::SixAxisSensorFusionParameters fusion_parameters{};
- const auto& controller =
- GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result =
- controller.GetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.PushRaw(fusion_parameters);
-}
-
-void Hid::ResetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- // Since these parameters are unknown just use what HW outputs
- const Core::HID::SixAxisSensorFusionParameters fusion_parameters{
- .parameter1 = 0.03f,
- .parameter2 = 0.4f,
- };
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result1 =
- controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
- const auto result2 = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle, true);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- if (result1.IsError()) {
- rb.Push(result1);
- return;
- }
- rb.Push(result2);
-}
-
-void Hid::SetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()};
- const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
- "applet_resource_user_id={}",
- sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index,
- drift_mode, applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::GetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result);
- rb.PushEnum(drift_mode);
-}
-
-void Hid::ResetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::IsSixAxisSensorAtRest(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- bool is_at_rest{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(is_at_rest);
-}
-
-void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- bool is_firmware_available{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle,
- is_firmware_available);
-
- LOG_WARNING(
- Service_HID,
- "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(is_firmware_available);
-}
-
-void Hid::EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- bool enabled;
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.EnableSixAxisSensorUnalteredPassthrough(
- parameters.sixaxis_handle, parameters.enabled);
-
- LOG_DEBUG(Service_HID,
- "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, "
- "applet_resource_user_id={}",
- parameters.enabled, parameters.sixaxis_handle.npad_type,
- parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
- parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- bool is_unaltered_sisxaxis_enabled{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled(
- parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled);
-
- LOG_DEBUG(
- Service_HID,
- "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result);
- rb.Push(is_unaltered_sisxaxis_enabled);
-}
-
-void Hid::LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- Core::HID::SixAxisSensorCalibrationParameter calibration{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result =
- controller.LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration);
-
- LOG_WARNING(
- Service_HID,
- "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- if (result.IsSuccess()) {
- ctx.WriteBuffer(calibration);
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::GetSixAxisSensorIcInformation(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- Core::HID::SixAxisSensorIcInformation ic_information{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result =
- controller.GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information);
-
- LOG_WARNING(
- Service_HID,
- "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- if (result.IsSuccess()) {
- ctx.WriteBuffer(ic_information);
- }
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::SixAxisSensorHandle sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result =
- controller.ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle);
-
- LOG_WARNING(
- Service_HID,
- "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
- parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::ActivateGesture(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- u32 unknown;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- applet_resource->ActivateController(HidController::Gesture);
-
- LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}",
- parameters.unknown, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetSupportedNpadStyleSet(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadStyleSet supported_styleset;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetSupportedStyleSet({parameters.supported_styleset});
-
- LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}",
- parameters.supported_styleset, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetSupportedNpadStyleSet(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .GetSupportedStyleSet()
- .raw);
-}
-
-void Hid::SetSupportedNpadIdType(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- const auto result = applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetSupportedNpadIdTypes(ctx.ReadBuffer());
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::ActivateNpad(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->ActivateController(HidController::NPad);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::DeactivateNpad(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->DeactivateController(HidController::NPad);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadIdType npad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- u64 unknown;
- };
- static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
- parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
-
- // Games expect this event to be signaled after calling this function
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SignalStyleSetChangedEvent(parameters.npad_id);
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .GetStyleSetChangedEvent(parameters.npad_id));
-}
-
-void Hid::DisconnectNpad(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadIdType npad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.DisconnectNpad(parameters.npad_id);
-
- LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
- parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetPlayerLedPattern(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
-
- Core::HID::LedPattern pattern{0, 0, 0, 0};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.GetLedPattern(npad_id, pattern);
-
- LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(pattern.raw);
-}
-
-void Hid::ActivateNpadWithRevision(HLERequestContext& ctx) {
- // Should have no effect with how our npad sets up the data
- IPC::RequestParser rp{ctx};
- struct Parameters {
- s32 revision;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- applet_resource->ActivateController(HidController::NPad);
-
- LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision,
- parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetNpadJoyHoldType(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()};
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
- applet_resource_user_id, hold_type);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetNpadJoyHoldType(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
-}
-
-void Hid::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadIdType npad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- Core::HID::NpadIdType new_npad_id{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.SetNpadMode(new_npad_id, parameters.npad_id,
- Controller_NPad::NpadJoyDeviceType::Left,
- Controller_NPad::NpadJoyAssignmentMode::Single);
-
- LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
- parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadIdType npad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
- };
- static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- Core::HID::NpadIdType new_npad_id{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
- Controller_NPad::NpadJoyAssignmentMode::Single);
-
- LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
- parameters.npad_id, parameters.applet_resource_user_id,
- parameters.npad_joy_device_type);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadIdType npad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- Core::HID::NpadIdType new_npad_id{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- controller.SetNpadMode(new_npad_id, parameters.npad_id, {},
- Controller_NPad::NpadJoyAssignmentMode::Dual);
-
- LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
- parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
- const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
-
- LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
- npad_id_1, npad_id_2, applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::StartLrAssignmentMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad).StartLRAssignmentMode();
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::StopLrAssignmentMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad).StopLRAssignmentMode();
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetNpadHandheldActivationMode(activation_mode);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}",
- applet_resource_user_id, activation_mode);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetNpadHandheldActivationMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .GetNpadHandheldActivationMode());
-}
-
-void Hid::SwapNpadAssignment(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
- const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SwapNpadAssignment(npad_id_1, npad_id_2);
-
- LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
- npad_id_1, npad_id_2, applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadIdType npad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- bool is_enabled = false;
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result =
- controller.IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled);
-
- LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
- parameters.npad_id, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result);
- rb.Push(is_enabled);
-}
-
-void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- bool is_enabled;
- INSERT_PADDING_BYTES_NOINIT(3);
- Core::HID::NpadIdType npad_id;
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled(
- parameters.is_enabled, parameters.npad_id);
-
- LOG_DEBUG(Service_HID,
- "(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}",
- parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadIdType npad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
- };
- static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- Core::HID::NpadIdType new_npad_id{};
- auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
- const auto is_reassigned =
- controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
- Controller_NPad::NpadJoyAssignmentMode::Single);
-
- LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
- parameters.npad_id, parameters.applet_resource_user_id,
- parameters.npad_joy_device_type);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(is_reassigned);
- rb.PushEnum(new_npad_id);
-}
-
-void Hid::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- bool analog_stick_use_center_clamp;
- INSERT_PADDING_BYTES_NOINIT(7);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- GetAppletResource()
- ->GetController<Controller_NPad>(HidController::NPad)
- .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
-
- LOG_WARNING(Service_HID,
- "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
- parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadStyleSet npad_styleset;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- Core::HID::NpadButton button;
- };
- static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_WARNING(Service_HID,
- "(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}",
- parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
- applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetVibrationDeviceInfo(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
- const auto& controller =
- GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
-
- Core::HID::VibrationDeviceInfo vibration_device_info;
- bool check_device_index = false;
-
- switch (vibration_device_handle.npad_type) {
- case Core::HID::NpadStyleIndex::ProController:
- case Core::HID::NpadStyleIndex::Handheld:
- case Core::HID::NpadStyleIndex::JoyconDual:
- case Core::HID::NpadStyleIndex::JoyconLeft:
- case Core::HID::NpadStyleIndex::JoyconRight:
- vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
- check_device_index = true;
- break;
- case Core::HID::NpadStyleIndex::GameCube:
- vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
- break;
- case Core::HID::NpadStyleIndex::N64:
- vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
- break;
- default:
- vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
- break;
- }
-
- vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
- if (check_device_index) {
- switch (vibration_device_handle.device_index) {
- case Core::HID::DeviceIndex::Left:
- vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
- break;
- case Core::HID::DeviceIndex::Right:
- vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
- break;
- case Core::HID::DeviceIndex::None:
- default:
- ASSERT_MSG(false, "DeviceIndex should never be None!");
- break;
- }
- }
-
- LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
- vibration_device_info.type, vibration_device_info.position);
-
- const auto result = controller.IsDeviceHandleValid(vibration_device_handle);
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.PushRaw(vibration_device_info);
-}
-
-void Hid::SendVibrationValue(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::VibrationDeviceHandle vibration_device_handle;
- Core::HID::VibrationValue vibration_value;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .VibrateController(parameters.vibration_device_handle, parameters.vibration_value);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.vibration_device_handle.npad_type,
- parameters.vibration_device_handle.npad_id,
- parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetActualVibrationValue(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::VibrationDeviceHandle vibration_device_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.vibration_device_handle.npad_type,
- parameters.vibration_device_handle.npad_id,
- parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(ResultSuccess);
- rb.PushRaw(applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .GetLastVibration(parameters.vibration_device_handle));
-}
-
-void Hid::CreateActiveVibrationDeviceList(HLERequestContext& ctx) {
- LOG_DEBUG(Service_HID, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IActiveVibrationDeviceList>(system, applet_resource);
-}
-
-void Hid::PermitVibration(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto can_vibrate{rp.Pop<bool>()};
-
- // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value
- // by converting it to a bool
- Settings::values.vibration_enabled.SetValue(can_vibrate);
-
- LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::IsVibrationPermitted(HLERequestContext& ctx) {
- LOG_DEBUG(Service_HID, "called");
-
- // nnSDK checks if a float is greater than zero. We return the bool we stored earlier
- const auto is_enabled = Settings::values.vibration_enabled.GetValue();
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(is_enabled);
-}
-
-void Hid::SendVibrationValues(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- const auto handle_data = ctx.ReadBuffer(0);
- const auto handle_count = ctx.GetReadBufferNumElements<Core::HID::VibrationDeviceHandle>(0);
- const auto vibration_data = ctx.ReadBuffer(1);
- const auto vibration_count = ctx.GetReadBufferNumElements<Core::HID::VibrationValue>(1);
-
- auto vibration_device_handles =
- std::span(reinterpret_cast<const Core::HID::VibrationDeviceHandle*>(handle_data.data()),
- handle_count);
- auto vibration_values = std::span(
- reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .VibrateControllers(vibration_device_handles, vibration_values);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SendVibrationGcErmCommand(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::VibrationDeviceHandle vibration_device_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- Core::HID::VibrationGcErmCommand gc_erm_command;
- };
- static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- /**
- * Note: This uses yuzu-specific behavior such that the StopHard command produces
- * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below,
- * in order to differentiate between Stop and StopHard commands.
- * This is done to reuse the controller vibration functions made for regular controllers.
- */
- const auto vibration_value = [parameters] {
- switch (parameters.gc_erm_command) {
- case Core::HID::VibrationGcErmCommand::Stop:
- return Core::HID::VibrationValue{
- .low_amplitude = 0.0f,
- .low_frequency = 160.0f,
- .high_amplitude = 0.0f,
- .high_frequency = 320.0f,
- };
- case Core::HID::VibrationGcErmCommand::Start:
- return Core::HID::VibrationValue{
- .low_amplitude = 1.0f,
- .low_frequency = 160.0f,
- .high_amplitude = 1.0f,
- .high_frequency = 320.0f,
- };
- case Core::HID::VibrationGcErmCommand::StopHard:
- return Core::HID::VibrationValue{
- .low_amplitude = 0.0f,
- .low_frequency = 0.0f,
- .high_amplitude = 0.0f,
- .high_frequency = 0.0f,
- };
- default:
- return Core::HID::DEFAULT_VIBRATION_VALUE;
- }
- }();
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .VibrateController(parameters.vibration_device_handle, vibration_value);
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
- "gc_erm_command={}",
- parameters.vibration_device_handle.npad_type,
- parameters.vibration_device_handle.npad_id,
- parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
- parameters.gc_erm_command);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::VibrationDeviceHandle vibration_device_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- const auto last_vibration = applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .GetLastVibration(parameters.vibration_device_handle);
-
- const auto gc_erm_command = [last_vibration] {
- if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
- return Core::HID::VibrationGcErmCommand::Start;
- }
-
- /**
- * Note: This uses yuzu-specific behavior such that the StopHard command produces
- * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function
- * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
- * This is done to reuse the controller vibration functions made for regular controllers.
- */
- if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) {
- return Core::HID::VibrationGcErmCommand::StopHard;
- }
-
- return Core::HID::VibrationGcErmCommand::Stop;
- }();
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.vibration_device_handle.npad_type,
- parameters.vibration_device_handle.npad_id,
- parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.PushEnum(gc_erm_command);
-}
-
-void Hid::BeginPermitVibrationSession(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetPermitVibrationSession(true);
-
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::EndPermitVibrationSession(HLERequestContext& ctx) {
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetPermitVibrationSession(false);
-
- LOG_DEBUG(Service_HID, "called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::IsVibrationDeviceMounted(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::VibrationDeviceHandle vibration_device_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_DEBUG(Service_HID,
- "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
- parameters.vibration_device_handle.npad_type,
- parameters.vibration_device_handle.npad_id,
- parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .IsVibrationDeviceMounted(parameters.vibration_device_handle));
-}
-
-void Hid::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->ActivateController(HidController::ConsoleSixAxisSensor);
-
- LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::StartConsoleSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_WARNING(Service_HID,
- "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
- parameters.console_sixaxis_handle.unknown_1,
- parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::StopConsoleSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_WARNING(Service_HID,
- "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
- parameters.console_sixaxis_handle.unknown_1,
- parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ActivateSevenSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->ActivateController(HidController::ConsoleSixAxisSensor);
-
- LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::StartSevenSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
- applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::StopSevenSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
- applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto t_mem_1_size{rp.Pop<u64>()};
- const auto t_mem_2_size{rp.Pop<u64>()};
- const auto t_mem_1_handle{ctx.GetCopyHandle(0)};
- const auto t_mem_2_handle{ctx.GetCopyHandle(1)};
-
- ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
- ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
-
- auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
- t_mem_1_handle);
-
- if (t_mem_1.IsNull()) {
- LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
- t_mem_2_handle);
-
- if (t_mem_2.IsNull()) {
- LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- ASSERT_MSG(t_mem_1->GetSize() == 0x1000, "t_mem_1 has incorrect size");
- ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size");
-
- // Activate console six axis controller
- applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
- .ActivateController();
-
- applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
- .SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
-
- LOG_WARNING(Service_HID,
- "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
- "applet_resource_user_id={}",
- t_mem_1_handle, t_mem_2_handle, applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::FinalizeSevenSixAxisSensor(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
- applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- applet_resource->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
- .ResetTimestamp();
-
- LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(false);
-}
-
-void Hid::GetPalmaConnectionHandle(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- Core::HID::NpadIdType npad_id;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
- parameters.npad_id, parameters.applet_resource_user_id);
-
- Controller_Palma::PalmaConnectionHandle handle;
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
- const auto result = controller.GetPalmaConnectionHandle(parameters.npad_id, handle);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.PushRaw(handle);
-}
-
-void Hid::InitializePalma(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
- const auto result = controller.InitializePalma(connection_handle);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(controller.AcquirePalmaOperationCompleteEvent(connection_handle));
-}
-
-void Hid::GetPalmaOperationInfo(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- Controller_Palma::PalmaOperationType operation_type;
- Controller_Palma::PalmaOperationData data;
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
- const auto result = controller.GetPalmaOperationInfo(connection_handle, operation_type, data);
-
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- ctx.WriteBuffer(data);
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result);
- rb.Push(static_cast<u64>(operation_type));
-}
-
-void Hid::PlayPalmaActivity(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
- const auto palma_activity{rp.Pop<u64>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, palma_activity={}",
- connection_handle.npad_id, palma_activity);
-
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
- const auto result = controller.PlayPalmaActivity(connection_handle, palma_activity);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::SetPalmaFrModeType(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
- const auto fr_mode{rp.PopEnum<Controller_Palma::PalmaFrModeType>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, fr_mode={}",
- connection_handle.npad_id, fr_mode);
-
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
- const auto result = controller.SetPalmaFrModeType(connection_handle, fr_mode);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::ReadPalmaStep(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
- const auto result = controller.ReadPalmaStep(connection_handle);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::EnablePalmaStep(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- bool is_enabled;
- INSERT_PADDING_WORDS_NOINIT(1);
- Controller_Palma::PalmaConnectionHandle connection_handle;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, is_enabled={}",
- parameters.connection_handle.npad_id, parameters.is_enabled);
-
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
- const auto result =
- controller.EnablePalmaStep(parameters.connection_handle, parameters.is_enabled);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::ResetPalmaStep(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- auto& controller = GetAppletResource()->GetController<Controller_Palma>(HidController::Palma);
- const auto result = controller.ResetPalmaStep(connection_handle);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::ReadPalmaApplicationSection(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::WritePalmaApplicationSection(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ReadPalmaUniqueCode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .ReadPalmaUniqueCode(connection_handle);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetPalmaUniqueCodeInvalid(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .SetPalmaUniqueCodeInvalid(connection_handle);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::WritePalmaActivityEntry(HLERequestContext& ctx) {
- LOG_CRITICAL(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
- const auto unknown{rp.Pop<u64>()};
-
- [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
- connection_handle.npad_id, unknown);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .WritePalmaRgbLedPatternEntry(connection_handle, unknown);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::WritePalmaWaveEntry(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
- const auto wave_set{rp.PopEnum<Controller_Palma::PalmaWaveSet>()};
- const auto unknown{rp.Pop<u64>()};
- const auto t_mem_size{rp.Pop<u64>()};
- const auto t_mem_handle{ctx.GetCopyHandle(0)};
- const auto size{rp.Pop<u64>()};
-
- ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
-
- auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
- t_mem_handle);
-
- if (t_mem.IsNull()) {
- LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- ASSERT_MSG(t_mem->GetSize() == 0x3000, "t_mem has incorrect size");
-
- LOG_WARNING(Service_HID,
- "(STUBBED) called, connection_handle={}, wave_set={}, unknown={}, "
- "t_mem_handle=0x{:08X}, t_mem_size={}, size={}",
- connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .WritePalmaWaveEntry(connection_handle, wave_set, t_mem->GetSourceAddress(), t_mem_size);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- s32 database_id_version;
- INSERT_PADDING_WORDS_NOINIT(1);
- Controller_Palma::PalmaConnectionHandle connection_handle;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, database_id_version={}",
- parameters.connection_handle.npad_id, parameters.database_id_version);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .SetPalmaDataBaseIdentificationVersion(parameters.connection_handle,
- parameters.database_id_version);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .GetPalmaDataBaseIdentificationVersion(connection_handle);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SuspendPalmaFeature(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetPalmaOperationResult(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- const auto result = applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .GetPalmaOperationResult(connection_handle);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
-}
-
-void Hid::ReadPalmaPlayLog(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::ResetPalmaPlayLog(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetIsPalmaAllConnectable(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- bool is_palma_all_connectable;
- INSERT_PADDING_BYTES_NOINIT(7);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_WARNING(Service_HID,
- "(STUBBED) called, is_palma_all_connectable={},applet_resource_user_id={}",
- parameters.is_palma_all_connectable, parameters.applet_resource_user_id);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .SetIsPalmaAllConnectable(parameters.is_palma_all_connectable);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetIsPalmaPairedConnectable(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::PairPalma(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .PairPalma(connection_handle);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetPalmaBoostMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto palma_boost_mode{rp.Pop<bool>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode);
-
- applet_resource->GetController<Controller_Palma>(HidController::Palma)
- .SetPalmaBoostMode(palma_boost_mode);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::CancelWritePalmaWaveEntry(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::EnablePalmaBoostMode(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetPalmaBluetoothAddress(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::SetNpadCommunicationMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()};
-
- applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .SetNpadCommunicationMode(communication_mode);
-
- LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}",
- applet_resource_user_id, communication_mode);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::GetNpadCommunicationMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
- .GetNpadCommunicationMode());
-}
-
-void Hid::SetTouchScreenConfiguration(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};
- const auto applet_resource_user_id{rp.Pop<u64>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}",
- touchscreen_mode.mode, applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void Hid::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- struct Parameters {
- s32 unknown;
- INSERT_PADDING_WORDS_NOINIT(1);
- u64 applet_resource_user_id;
- };
- static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
-
- const auto parameters{rp.PopRaw<Parameters>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}",
- parameters.unknown, parameters.applet_resource_user_id);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(false);
-}
-
-class HidDbg final : public ServiceFramework<HidDbg> {
-public:
- explicit HidDbg(Core::System& system_) : ServiceFramework{system_, "hid:dbg"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "DeactivateDebugPad"},
- {1, nullptr, "SetDebugPadAutoPilotState"},
- {2, nullptr, "UnsetDebugPadAutoPilotState"},
- {10, nullptr, "DeactivateTouchScreen"},
- {11, nullptr, "SetTouchScreenAutoPilotState"},
- {12, nullptr, "UnsetTouchScreenAutoPilotState"},
- {13, nullptr, "GetTouchScreenConfiguration"},
- {14, nullptr, "ProcessTouchScreenAutoTune"},
- {15, nullptr, "ForceStopTouchScreenManagement"},
- {16, nullptr, "ForceRestartTouchScreenManagement"},
- {17, nullptr, "IsTouchScreenManaged"},
- {20, nullptr, "DeactivateMouse"},
- {21, nullptr, "SetMouseAutoPilotState"},
- {22, nullptr, "UnsetMouseAutoPilotState"},
- {25, nullptr, "SetDebugMouseAutoPilotState"},
- {26, nullptr, "UnsetDebugMouseAutoPilotState"},
- {30, nullptr, "DeactivateKeyboard"},
- {31, nullptr, "SetKeyboardAutoPilotState"},
- {32, nullptr, "UnsetKeyboardAutoPilotState"},
- {50, nullptr, "DeactivateXpad"},
- {51, nullptr, "SetXpadAutoPilotState"},
- {52, nullptr, "UnsetXpadAutoPilotState"},
- {53, nullptr, "DeactivateJoyXpad"},
- {60, nullptr, "ClearNpadSystemCommonPolicy"},
- {61, nullptr, "DeactivateNpad"},
- {62, nullptr, "ForceDisconnectNpad"},
- {91, nullptr, "DeactivateGesture"},
- {110, nullptr, "DeactivateHomeButton"},
- {111, nullptr, "SetHomeButtonAutoPilotState"},
- {112, nullptr, "UnsetHomeButtonAutoPilotState"},
- {120, nullptr, "DeactivateSleepButton"},
- {121, nullptr, "SetSleepButtonAutoPilotState"},
- {122, nullptr, "UnsetSleepButtonAutoPilotState"},
- {123, nullptr, "DeactivateInputDetector"},
- {130, nullptr, "DeactivateCaptureButton"},
- {131, nullptr, "SetCaptureButtonAutoPilotState"},
- {132, nullptr, "UnsetCaptureButtonAutoPilotState"},
- {133, nullptr, "SetShiftAccelerometerCalibrationValue"},
- {134, nullptr, "GetShiftAccelerometerCalibrationValue"},
- {135, nullptr, "SetShiftGyroscopeCalibrationValue"},
- {136, nullptr, "GetShiftGyroscopeCalibrationValue"},
- {140, nullptr, "DeactivateConsoleSixAxisSensor"},
- {141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
- {142, nullptr, "DeactivateSevenSixAxisSensor"},
- {143, nullptr, "GetConsoleSixAxisSensorCountStates"},
- {144, nullptr, "GetAccelerometerFsr"},
- {145, nullptr, "SetAccelerometerFsr"},
- {146, nullptr, "GetAccelerometerOdr"},
- {147, nullptr, "SetAccelerometerOdr"},
- {148, nullptr, "GetGyroscopeFsr"},
- {149, nullptr, "SetGyroscopeFsr"},
- {150, nullptr, "GetGyroscopeOdr"},
- {151, nullptr, "SetGyroscopeOdr"},
- {152, nullptr, "GetWhoAmI"},
- {201, nullptr, "ActivateFirmwareUpdate"},
- {202, nullptr, "DeactivateFirmwareUpdate"},
- {203, nullptr, "StartFirmwareUpdate"},
- {204, nullptr, "GetFirmwareUpdateStage"},
- {205, nullptr, "GetFirmwareVersion"},
- {206, nullptr, "GetDestinationFirmwareVersion"},
- {207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
- {208, nullptr, "StartFirmwareUpdateForRevert"},
- {209, nullptr, "GetAvailableFirmwareVersionForRevert"},
- {210, nullptr, "IsFirmwareUpdatingDevice"},
- {211, nullptr, "StartFirmwareUpdateIndividual"},
- {215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
- {216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
- {221, nullptr, "UpdateControllerColor"},
- {222, nullptr, "ConnectUsbPadsAsync"},
- {223, nullptr, "DisconnectUsbPadsAsync"},
- {224, nullptr, "UpdateDesignInfo"},
- {225, nullptr, "GetUniquePadDriverState"},
- {226, nullptr, "GetSixAxisSensorDriverStates"},
- {227, nullptr, "GetRxPacketHistory"},
- {228, nullptr, "AcquireOperationEventHandle"},
- {229, nullptr, "ReadSerialFlash"},
- {230, nullptr, "WriteSerialFlash"},
- {231, nullptr, "GetOperationResult"},
- {232, nullptr, "EnableShipmentMode"},
- {233, nullptr, "ClearPairingInfo"},
- {234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
- {235, nullptr, "EnableAnalogStickPower"},
- {236, nullptr, "RequestKuinaUartClockCal"},
- {237, nullptr, "GetKuinaUartClockCal"},
- {238, nullptr, "SetKuinaUartClockTrim"},
- {239, nullptr, "KuinaLoopbackTest"},
- {240, nullptr, "RequestBatteryVoltage"},
- {241, nullptr, "GetBatteryVoltage"},
- {242, nullptr, "GetUniquePadPowerInfo"},
- {243, nullptr, "RebootUniquePad"},
- {244, nullptr, "RequestKuinaFirmwareVersion"},
- {245, nullptr, "GetKuinaFirmwareVersion"},
- {246, nullptr, "GetVidPid"},
- {247, nullptr, "GetAnalogStickCalibrationValue"},
- {248, nullptr, "GetUniquePadIdsFull"},
- {249, nullptr, "ConnectUniquePad"},
- {250, nullptr, "IsVirtual"},
- {251, nullptr, "GetAnalogStickModuleParam"},
- {301, nullptr, "GetAbstractedPadHandles"},
- {302, nullptr, "GetAbstractedPadState"},
- {303, nullptr, "GetAbstractedPadsState"},
- {321, nullptr, "SetAutoPilotVirtualPadState"},
- {322, nullptr, "UnsetAutoPilotVirtualPadState"},
- {323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
- {324, nullptr, "AttachHdlsWorkBuffer"},
- {325, nullptr, "ReleaseHdlsWorkBuffer"},
- {326, nullptr, "DumpHdlsNpadAssignmentState"},
- {327, nullptr, "DumpHdlsStates"},
- {328, nullptr, "ApplyHdlsNpadAssignmentState"},
- {329, nullptr, "ApplyHdlsStateList"},
- {330, nullptr, "AttachHdlsVirtualDevice"},
- {331, nullptr, "DetachHdlsVirtualDevice"},
- {332, nullptr, "SetHdlsState"},
- {350, nullptr, "AddRegisteredDevice"},
- {400, nullptr, "DisableExternalMcuOnNxDevice"},
- {401, nullptr, "DisableRailDeviceFiltering"},
- {402, nullptr, "EnableWiredPairing"},
- {403, nullptr, "EnableShipmentModeAutoClear"},
- {404, nullptr, "SetRailEnabled"},
- {500, nullptr, "SetFactoryInt"},
- {501, nullptr, "IsFactoryBootEnabled"},
- {550, nullptr, "SetAnalogStickModelDataTemporarily"},
- {551, nullptr, "GetAnalogStickModelData"},
- {552, nullptr, "ResetAnalogStickModelData"},
- {600, nullptr, "ConvertPadState"},
- {650, nullptr, "AddButtonPlayData"},
- {651, nullptr, "StartButtonPlayData"},
- {652, nullptr, "StopButtonPlayData"},
- {2000, nullptr, "DeactivateDigitizer"},
- {2001, nullptr, "SetDigitizerAutoPilotState"},
- {2002, nullptr, "UnsetDigitizerAutoPilotState"},
- {2002, nullptr, "ReloadFirmwareDebugSettings"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-};
-
-class HidSys final : public ServiceFramework<HidSys> {
-public:
- explicit HidSys(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_)
- : ServiceFramework{system_, "hid:sys"}, service_context{system_, "hid:sys"},
- applet_resource{applet_resource_} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {31, nullptr, "SendKeyboardLockKeyEvent"},
- {101, nullptr, "AcquireHomeButtonEventHandle"},
- {111, nullptr, "ActivateHomeButton"},
- {121, nullptr, "AcquireSleepButtonEventHandle"},
- {131, nullptr, "ActivateSleepButton"},
- {141, nullptr, "AcquireCaptureButtonEventHandle"},
- {151, nullptr, "ActivateCaptureButton"},
- {161, nullptr, "GetPlatformConfig"},
- {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
- {211, nullptr, "GetNpadsWithNfc"},
- {212, nullptr, "AcquireNfcActivateEventHandle"},
- {213, nullptr, "ActivateNfc"},
- {214, nullptr, "GetXcdHandleForNpadWithNfc"},
- {215, nullptr, "IsNfcActivated"},
- {230, nullptr, "AcquireIrSensorEventHandle"},
- {231, nullptr, "ActivateIrSensor"},
- {232, nullptr, "GetIrSensorState"},
- {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
- {301, nullptr, "ActivateNpadSystem"},
- {303, &HidSys::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
- {304, nullptr, "EnableAssigningSingleOnSlSrPress"},
- {305, nullptr, "DisableAssigningSingleOnSlSrPress"},
- {306, &HidSys::GetLastActiveNpad, "GetLastActiveNpad"},
- {307, nullptr, "GetNpadSystemExtStyle"},
- {308, nullptr, "ApplyNpadSystemCommonPolicyFull"},
- {309, nullptr, "GetNpadFullKeyGripColor"},
- {310, nullptr, "GetMaskedSupportedNpadStyleSet"},
- {311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
- {312, nullptr, "SetSupportedNpadStyleSetAll"},
- {313, nullptr, "GetNpadCaptureButtonAssignment"},
- {314, nullptr, "GetAppletFooterUiType"},
- {315, nullptr, "GetAppletDetailedUiType"},
- {316, nullptr, "GetNpadInterfaceType"},
- {317, nullptr, "GetNpadLeftRightInterfaceType"},
- {318, nullptr, "HasBattery"},
- {319, nullptr, "HasLeftRightBattery"},
- {321, &HidSys::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
- {322, nullptr, "GetIrSensorState"},
- {323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
- {324, nullptr, "GetUniquePadButtonSet"},
- {325, nullptr, "GetUniquePadColor"},
- {326, nullptr, "GetUniquePadAppletDetailedUiType"},
- {327, nullptr, "GetAbstractedPadIdDataFromNpad"},
- {328, nullptr, "AttachAbstractedPadToNpad"},
- {329, nullptr, "DetachAbstractedPadAll"},
- {330, nullptr, "CheckAbstractedPadConnection"},
- {500, nullptr, "SetAppletResourceUserId"},
- {501, nullptr, "RegisterAppletResourceUserId"},
- {502, nullptr, "UnregisterAppletResourceUserId"},
- {503, nullptr, "EnableAppletToGetInput"},
- {504, nullptr, "SetAruidValidForVibration"},
- {505, nullptr, "EnableAppletToGetSixAxisSensor"},
- {506, nullptr, "EnableAppletToGetPadInput"},
- {507, nullptr, "EnableAppletToGetTouchScreen"},
- {510, nullptr, "SetVibrationMasterVolume"},
- {511, nullptr, "GetVibrationMasterVolume"},
- {512, nullptr, "BeginPermitVibrationSession"},
- {513, nullptr, "EndPermitVibrationSession"},
- {514, nullptr, "Unknown514"},
- {520, nullptr, "EnableHandheldHids"},
- {521, nullptr, "DisableHandheldHids"},
- {522, nullptr, "SetJoyConRailEnabled"},
- {523, nullptr, "IsJoyConRailEnabled"},
- {524, nullptr, "IsHandheldHidsEnabled"},
- {525, nullptr, "IsJoyConAttachedOnAllRail"},
- {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
- {541, nullptr, "GetPlayReportControllerUsages"},
- {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
- {543, nullptr, "GetRegisteredDevicesOld"},
- {544, nullptr, "AcquireConnectionTriggerTimeoutEvent"},
- {545, nullptr, "SendConnectionTrigger"},
- {546, nullptr, "AcquireDeviceRegisteredEventForControllerSupport"},
- {547, nullptr, "GetAllowedBluetoothLinksCount"},
- {548, nullptr, "GetRegisteredDevices"},
- {549, nullptr, "GetConnectableRegisteredDevices"},
- {700, nullptr, "ActivateUniquePad"},
- {702, nullptr, "AcquireUniquePadConnectionEventHandle"},
- {703, nullptr, "GetUniquePadIds"},
- {751, &HidSys::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
- {800, nullptr, "ListSixAxisSensorHandles"},
- {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
- {802, nullptr, "ResetSixAxisSensorCalibrationValues"},
- {803, nullptr, "StartSixAxisSensorUserCalibration"},
- {804, nullptr, "CancelSixAxisSensorUserCalibration"},
- {805, nullptr, "GetUniquePadBluetoothAddress"},
- {806, nullptr, "DisconnectUniquePad"},
- {807, nullptr, "GetUniquePadType"},
- {808, nullptr, "GetUniquePadInterface"},
- {809, nullptr, "GetUniquePadSerialNumber"},
- {810, nullptr, "GetUniquePadControllerNumber"},
- {811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
- {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
- {821, nullptr, "StartAnalogStickManualCalibration"},
- {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
- {823, nullptr, "CancelAnalogStickManualCalibration"},
- {824, nullptr, "ResetAnalogStickManualCalibration"},
- {825, nullptr, "GetAnalogStickState"},
- {826, nullptr, "GetAnalogStickManualCalibrationStage"},
- {827, nullptr, "IsAnalogStickButtonPressed"},
- {828, nullptr, "IsAnalogStickInReleasePosition"},
- {829, nullptr, "IsAnalogStickInCircumference"},
- {830, nullptr, "SetNotificationLedPattern"},
- {831, nullptr, "SetNotificationLedPatternWithTimeout"},
- {832, nullptr, "PrepareHidsForNotificationWake"},
- {850, &HidSys::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
- {851, nullptr, "EnableUsbFullKeyController"},
- {852, nullptr, "IsUsbConnected"},
- {870, nullptr, "IsHandheldButtonPressedOnConsoleMode"},
- {900, nullptr, "ActivateInputDetector"},
- {901, nullptr, "NotifyInputDetector"},
- {1000, nullptr, "InitializeFirmwareUpdate"},
- {1001, nullptr, "GetFirmwareVersion"},
- {1002, nullptr, "GetAvailableFirmwareVersion"},
- {1003, nullptr, "IsFirmwareUpdateAvailable"},
- {1004, nullptr, "CheckFirmwareUpdateRequired"},
- {1005, nullptr, "StartFirmwareUpdate"},
- {1006, nullptr, "AbortFirmwareUpdate"},
- {1007, nullptr, "GetFirmwareUpdateState"},
- {1008, nullptr, "ActivateAudioControl"},
- {1009, nullptr, "AcquireAudioControlEventHandle"},
- {1010, nullptr, "GetAudioControlStates"},
- {1011, nullptr, "DeactivateAudioControl"},
- {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
- {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
- {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
- {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
- {1100, nullptr, "GetHidbusSystemServiceObject"},
- {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
- {1130, nullptr, "InitializeUsbFirmwareUpdate"},
- {1131, nullptr, "FinalizeUsbFirmwareUpdate"},
- {1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
- {1133, nullptr, "StartUsbFirmwareUpdate"},
- {1134, nullptr, "GetUsbFirmwareUpdateState"},
- {1150, nullptr, "SetTouchScreenMagnification"},
- {1151, nullptr, "GetTouchScreenFirmwareVersion"},
- {1152, nullptr, "SetTouchScreenDefaultConfiguration"},
- {1153, &HidSys::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
- {1154, nullptr, "IsFirmwareAvailableForNotification"},
- {1155, nullptr, "SetForceHandheldStyleVibration"},
- {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
- {1157, nullptr, "CancelConnectionTrigger"},
- {1200, nullptr, "IsButtonConfigSupported"},
- {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
- {1202, nullptr, "DeleteButtonConfig"},
- {1203, nullptr, "DeleteButtonConfigEmbedded"},
- {1204, nullptr, "SetButtonConfigEnabled"},
- {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
- {1206, nullptr, "IsButtonConfigEnabled"},
- {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
- {1208, nullptr, "SetButtonConfigEmbedded"},
- {1209, nullptr, "SetButtonConfigFull"},
- {1210, nullptr, "SetButtonConfigLeft"},
- {1211, nullptr, "SetButtonConfigRight"},
- {1212, nullptr, "GetButtonConfigEmbedded"},
- {1213, nullptr, "GetButtonConfigFull"},
- {1214, nullptr, "GetButtonConfigLeft"},
- {1215, nullptr, "GetButtonConfigRight"},
- {1250, nullptr, "IsCustomButtonConfigSupported"},
- {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
- {1252, nullptr, "IsDefaultButtonConfigFull"},
- {1253, nullptr, "IsDefaultButtonConfigLeft"},
- {1254, nullptr, "IsDefaultButtonConfigRight"},
- {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
- {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
- {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
- {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
- {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
- {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
- {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
- {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
- {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
- {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
- {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
- {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
- {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
- {1268, nullptr, "DeleteButtonConfigStorageFull"},
- {1269, nullptr, "DeleteButtonConfigStorageLeft"},
- {1270, nullptr, "DeleteButtonConfigStorageRight"},
- {1271, nullptr, "IsUsingCustomButtonConfig"},
- {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
- {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
- {1274, nullptr, "SetDefaultButtonConfig"},
- {1275, nullptr, "SetAllDefaultButtonConfig"},
- {1276, nullptr, "SetHidButtonConfigEmbedded"},
- {1277, nullptr, "SetHidButtonConfigFull"},
- {1278, nullptr, "SetHidButtonConfigLeft"},
- {1279, nullptr, "SetHidButtonConfigRight"},
- {1280, nullptr, "GetHidButtonConfigEmbedded"},
- {1281, nullptr, "GetHidButtonConfigFull"},
- {1282, nullptr, "GetHidButtonConfigLeft"},
- {1283, nullptr, "GetHidButtonConfigRight"},
- {1284, nullptr, "GetButtonConfigStorageEmbedded"},
- {1285, nullptr, "GetButtonConfigStorageFull"},
- {1286, nullptr, "GetButtonConfigStorageLeft"},
- {1287, nullptr, "GetButtonConfigStorageRight"},
- {1288, nullptr, "SetButtonConfigStorageEmbedded"},
- {1289, nullptr, "SetButtonConfigStorageFull"},
- {1290, nullptr, "DeleteButtonConfigStorageRight"},
- {1291, nullptr, "DeleteButtonConfigStorageRight"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-
- joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent");
- }
-
- ~HidSys() {
- service_context.CloseEvent(joy_detach_event);
- };
-
-private:
- void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "called");
-
- GetAppletResource()
- ->GetController<Controller_NPad>(HidController::NPad)
- .ApplyNpadSystemCommonPolicy();
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetLastActiveNpad(HLERequestContext& ctx) {
- LOG_DEBUG(Service_HID, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(system.HIDCore().GetLastActiveController());
- }
-
- void GetUniquePadsFromNpad(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
-
- LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type);
-
- const std::vector<Core::HID::UniquePadId> unique_pads{};
-
- ctx.WriteBuffer(unique_pads);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(static_cast<u32>(unique_pads.size()));
- }
-
- void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
- LOG_INFO(Service_AM, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
- }
-
- void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
- const bool is_enabled = false;
-
- LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(is_enabled);
- }
-
- void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
- LOG_WARNING(Service_HID, "(STUBBED) called");
-
- Core::HID::TouchScreenConfigurationForNx touchscreen_config{
- .mode = Core::HID::TouchScreenModeForNx::Finger,
- };
-
- if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
- touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
- touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
- }
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(ResultSuccess);
- rb.PushRaw(touchscreen_config);
- }
-
- std::shared_ptr<IAppletResource> GetAppletResource() {
- if (applet_resource == nullptr) {
- applet_resource = std::make_shared<IAppletResource>(system, service_context);
- }
-
- return applet_resource;
- }
-
- Kernel::KEvent* joy_detach_event;
- KernelHelpers::ServiceContext service_context;
- std::shared_ptr<IAppletResource> applet_resource;
-};
-
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
- std::shared_ptr<IAppletResource> applet_resource;
+ std::shared_ptr<ResourceManager> resouce_manager = std::make_shared<ResourceManager>(system);
+ std::shared_ptr<HidFirmwareSettings> firmware_settings =
+ std::make_shared<HidFirmwareSettings>();
+
+ server_manager->RegisterNamedService(
+ "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings));
+ server_manager->RegisterNamedService(
+ "hid:dbg", std::make_shared<IHidDebugServer>(system, resouce_manager));
+ server_manager->RegisterNamedService(
+ "hid:sys", std::make_shared<IHidSystemServer>(system, resouce_manager));
- server_manager->RegisterNamedService("hid", std::make_shared<Hid>(system, applet_resource));
server_manager->RegisterNamedService("hidbus", std::make_shared<HidBus>(system));
- server_manager->RegisterNamedService("hid:dbg", std::make_shared<HidDbg>(system));
- server_manager->RegisterNamedService("hid:sys",
- std::make_shared<HidSys>(system, applet_resource));
- server_manager->RegisterNamedService("irs", std::make_shared<Service::IRS::IRS>(system));
- server_manager->RegisterNamedService("irs:sys",
- std::make_shared<Service::IRS::IRS_SYS>(system));
+ server_manager->RegisterNamedService("irs", std::make_shared<IRS::IRS>(system));
+ server_manager->RegisterNamedService("irs:sys", std::make_shared<IRS::IRS_SYS>(system));
server_manager->RegisterNamedService("xcd:sys", std::make_shared<XCD_SYS>(system));
+
system.RunServer(std::move(server_manager));
}
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 @@
#pragma once
-#include <chrono>
-
-#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/service.h"
-
-namespace Core::Timing {
-struct EventType;
-}
-
-namespace Service::SM {
-class ServiceManager;
+namespace Core {
+class System;
}
namespace Service::HID {
-enum class HidController : std::size_t {
- DebugPad,
- Touchscreen,
- Mouse,
- Keyboard,
- XPad,
- HomeButton,
- SleepButton,
- CaptureButton,
- InputDetector,
- UniquePad,
- NPad,
- Gesture,
- ConsoleSixAxisSensor,
- DebugMouse,
- Palma,
-
- MaxControllers,
-};
-
-class IAppletResource final : public ServiceFramework<IAppletResource> {
-public:
- explicit IAppletResource(Core::System& system_,
- KernelHelpers::ServiceContext& service_context_);
- ~IAppletResource() override;
-
- void ActivateController(HidController controller);
- void DeactivateController(HidController controller);
-
- template <typename T>
- T& GetController(HidController controller) {
- return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
- }
-
- template <typename T>
- const T& GetController(HidController controller) const {
- return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
- }
-
-private:
- template <typename T>
- void MakeController(HidController controller, u8* shared_memory) {
- if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
- controllers[static_cast<std::size_t>(controller)] =
- std::make_unique<T>(system, shared_memory);
- } else {
- controllers[static_cast<std::size_t>(controller)] =
- std::make_unique<T>(system.HIDCore(), shared_memory);
- }
- }
-
- template <typename T>
- void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
- controllers[static_cast<std::size_t>(controller)] =
- std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
- }
-
- void GetSharedMemoryHandle(HLERequestContext& ctx);
- void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
- void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
- void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
- void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
-
- KernelHelpers::ServiceContext& service_context;
-
- std::shared_ptr<Core::Timing::EventType> npad_update_event;
- std::shared_ptr<Core::Timing::EventType> default_update_event;
- std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
- std::shared_ptr<Core::Timing::EventType> motion_update_event;
-
- std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
- controllers{};
-};
-
-class Hid final : public ServiceFramework<Hid> {
-public:
- explicit Hid(Core::System& system_, std::shared_ptr<IAppletResource> applet_resource_);
- ~Hid() override;
-
- std::shared_ptr<IAppletResource> GetAppletResource();
-
-private:
- void CreateAppletResource(HLERequestContext& ctx);
- void ActivateDebugPad(HLERequestContext& ctx);
- void ActivateTouchScreen(HLERequestContext& ctx);
- void ActivateMouse(HLERequestContext& ctx);
- void ActivateKeyboard(HLERequestContext& ctx);
- void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
- void ActivateXpad(HLERequestContext& ctx);
- void GetXpadIDs(HLERequestContext& ctx);
- void ActivateSixAxisSensor(HLERequestContext& ctx);
- void DeactivateSixAxisSensor(HLERequestContext& ctx);
- void StartSixAxisSensor(HLERequestContext& ctx);
- void StopSixAxisSensor(HLERequestContext& ctx);
- void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
- void EnableSixAxisSensorFusion(HLERequestContext& ctx);
- void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
- void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
- void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
- void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
- void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
- void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
- void IsSixAxisSensorAtRest(HLERequestContext& ctx);
- void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
- void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
- void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
- void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
- void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
- void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
- void ActivateGesture(HLERequestContext& ctx);
- void SetSupportedNpadStyleSet(HLERequestContext& ctx);
- void GetSupportedNpadStyleSet(HLERequestContext& ctx);
- void SetSupportedNpadIdType(HLERequestContext& ctx);
- void ActivateNpad(HLERequestContext& ctx);
- void DeactivateNpad(HLERequestContext& ctx);
- void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
- void DisconnectNpad(HLERequestContext& ctx);
- void GetPlayerLedPattern(HLERequestContext& ctx);
- void ActivateNpadWithRevision(HLERequestContext& ctx);
- void SetNpadJoyHoldType(HLERequestContext& ctx);
- void GetNpadJoyHoldType(HLERequestContext& ctx);
- void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
- void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
- void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
- void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
- void StartLrAssignmentMode(HLERequestContext& ctx);
- void StopLrAssignmentMode(HLERequestContext& ctx);
- void SetNpadHandheldActivationMode(HLERequestContext& ctx);
- void GetNpadHandheldActivationMode(HLERequestContext& ctx);
- void SwapNpadAssignment(HLERequestContext& ctx);
- void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
- void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
- void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
- void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
- void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
- void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
- void GetVibrationDeviceInfo(HLERequestContext& ctx);
- void SendVibrationValue(HLERequestContext& ctx);
- void GetActualVibrationValue(HLERequestContext& ctx);
- void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
- void PermitVibration(HLERequestContext& ctx);
- void IsVibrationPermitted(HLERequestContext& ctx);
- void SendVibrationValues(HLERequestContext& ctx);
- void SendVibrationGcErmCommand(HLERequestContext& ctx);
- void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
- void BeginPermitVibrationSession(HLERequestContext& ctx);
- void EndPermitVibrationSession(HLERequestContext& ctx);
- void IsVibrationDeviceMounted(HLERequestContext& ctx);
- void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
- void StartConsoleSixAxisSensor(HLERequestContext& ctx);
- void StopConsoleSixAxisSensor(HLERequestContext& ctx);
- void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
- void StartSevenSixAxisSensor(HLERequestContext& ctx);
- void StopSevenSixAxisSensor(HLERequestContext& ctx);
- void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
- void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
- void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
- void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
- void GetPalmaConnectionHandle(HLERequestContext& ctx);
- void InitializePalma(HLERequestContext& ctx);
- void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
- void GetPalmaOperationInfo(HLERequestContext& ctx);
- void PlayPalmaActivity(HLERequestContext& ctx);
- void SetPalmaFrModeType(HLERequestContext& ctx);
- void ReadPalmaStep(HLERequestContext& ctx);
- void EnablePalmaStep(HLERequestContext& ctx);
- void ResetPalmaStep(HLERequestContext& ctx);
- void ReadPalmaApplicationSection(HLERequestContext& ctx);
- void WritePalmaApplicationSection(HLERequestContext& ctx);
- void ReadPalmaUniqueCode(HLERequestContext& ctx);
- void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
- void WritePalmaActivityEntry(HLERequestContext& ctx);
- void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
- void WritePalmaWaveEntry(HLERequestContext& ctx);
- void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
- void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
- void SuspendPalmaFeature(HLERequestContext& ctx);
- void GetPalmaOperationResult(HLERequestContext& ctx);
- void ReadPalmaPlayLog(HLERequestContext& ctx);
- void ResetPalmaPlayLog(HLERequestContext& ctx);
- void SetIsPalmaAllConnectable(HLERequestContext& ctx);
- void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
- void PairPalma(HLERequestContext& ctx);
- void SetPalmaBoostMode(HLERequestContext& ctx);
- void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
- void EnablePalmaBoostMode(HLERequestContext& ctx);
- void GetPalmaBluetoothAddress(HLERequestContext& ctx);
- void SetDisallowedPalmaConnection(HLERequestContext& ctx);
- void SetNpadCommunicationMode(HLERequestContext& ctx);
- void GetNpadCommunicationMode(HLERequestContext& ctx);
- void SetTouchScreenConfiguration(HLERequestContext& ctx);
- void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
-
- std::shared_ptr<IAppletResource> applet_resource;
-
- KernelHelpers::ServiceContext service_context;
-};
-
void LoopProcess(Core::System& system);
} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/hid/hid_debug_server.h"
+#include "core/hle/service/hid/resource_manager.h"
+#include "core/hle/service/ipc_helpers.h"
+
+namespace Service::HID {
+
+IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
+ : ServiceFramework{system_, "hid:dbg"}, resource_manager{resource} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "DeactivateDebugPad"},
+ {1, nullptr, "SetDebugPadAutoPilotState"},
+ {2, nullptr, "UnsetDebugPadAutoPilotState"},
+ {10, nullptr, "DeactivateTouchScreen"},
+ {11, nullptr, "SetTouchScreenAutoPilotState"},
+ {12, nullptr, "UnsetTouchScreenAutoPilotState"},
+ {13, nullptr, "GetTouchScreenConfiguration"},
+ {14, nullptr, "ProcessTouchScreenAutoTune"},
+ {15, nullptr, "ForceStopTouchScreenManagement"},
+ {16, nullptr, "ForceRestartTouchScreenManagement"},
+ {17, nullptr, "IsTouchScreenManaged"},
+ {20, nullptr, "DeactivateMouse"},
+ {21, nullptr, "SetMouseAutoPilotState"},
+ {22, nullptr, "UnsetMouseAutoPilotState"},
+ {25, nullptr, "SetDebugMouseAutoPilotState"},
+ {26, nullptr, "UnsetDebugMouseAutoPilotState"},
+ {30, nullptr, "DeactivateKeyboard"},
+ {31, nullptr, "SetKeyboardAutoPilotState"},
+ {32, nullptr, "UnsetKeyboardAutoPilotState"},
+ {50, nullptr, "DeactivateXpad"},
+ {51, nullptr, "SetXpadAutoPilotState"},
+ {52, nullptr, "UnsetXpadAutoPilotState"},
+ {53, nullptr, "DeactivateJoyXpad"},
+ {60, nullptr, "ClearNpadSystemCommonPolicy"},
+ {61, nullptr, "DeactivateNpad"},
+ {62, nullptr, "ForceDisconnectNpad"},
+ {91, nullptr, "DeactivateGesture"},
+ {110, nullptr, "DeactivateHomeButton"},
+ {111, nullptr, "SetHomeButtonAutoPilotState"},
+ {112, nullptr, "UnsetHomeButtonAutoPilotState"},
+ {120, nullptr, "DeactivateSleepButton"},
+ {121, nullptr, "SetSleepButtonAutoPilotState"},
+ {122, nullptr, "UnsetSleepButtonAutoPilotState"},
+ {123, nullptr, "DeactivateInputDetector"},
+ {130, nullptr, "DeactivateCaptureButton"},
+ {131, nullptr, "SetCaptureButtonAutoPilotState"},
+ {132, nullptr, "UnsetCaptureButtonAutoPilotState"},
+ {133, nullptr, "SetShiftAccelerometerCalibrationValue"},
+ {134, nullptr, "GetShiftAccelerometerCalibrationValue"},
+ {135, nullptr, "SetShiftGyroscopeCalibrationValue"},
+ {136, nullptr, "GetShiftGyroscopeCalibrationValue"},
+ {140, nullptr, "DeactivateConsoleSixAxisSensor"},
+ {141, nullptr, "GetConsoleSixAxisSensorSamplingFrequency"},
+ {142, nullptr, "DeactivateSevenSixAxisSensor"},
+ {143, nullptr, "GetConsoleSixAxisSensorCountStates"},
+ {144, nullptr, "GetAccelerometerFsr"},
+ {145, nullptr, "SetAccelerometerFsr"},
+ {146, nullptr, "GetAccelerometerOdr"},
+ {147, nullptr, "SetAccelerometerOdr"},
+ {148, nullptr, "GetGyroscopeFsr"},
+ {149, nullptr, "SetGyroscopeFsr"},
+ {150, nullptr, "GetGyroscopeOdr"},
+ {151, nullptr, "SetGyroscopeOdr"},
+ {152, nullptr, "GetWhoAmI"},
+ {201, nullptr, "ActivateFirmwareUpdate"},
+ {202, nullptr, "DeactivateFirmwareUpdate"},
+ {203, nullptr, "StartFirmwareUpdate"},
+ {204, nullptr, "GetFirmwareUpdateStage"},
+ {205, nullptr, "GetFirmwareVersion"},
+ {206, nullptr, "GetDestinationFirmwareVersion"},
+ {207, nullptr, "DiscardFirmwareInfoCacheForRevert"},
+ {208, nullptr, "StartFirmwareUpdateForRevert"},
+ {209, nullptr, "GetAvailableFirmwareVersionForRevert"},
+ {210, nullptr, "IsFirmwareUpdatingDevice"},
+ {211, nullptr, "StartFirmwareUpdateIndividual"},
+ {215, nullptr, "SetUsbFirmwareForceUpdateEnabled"},
+ {216, nullptr, "SetAllKuinaDevicesToFirmwareUpdateMode"},
+ {221, nullptr, "UpdateControllerColor"},
+ {222, nullptr, "ConnectUsbPadsAsync"},
+ {223, nullptr, "DisconnectUsbPadsAsync"},
+ {224, nullptr, "UpdateDesignInfo"},
+ {225, nullptr, "GetUniquePadDriverState"},
+ {226, nullptr, "GetSixAxisSensorDriverStates"},
+ {227, nullptr, "GetRxPacketHistory"},
+ {228, nullptr, "AcquireOperationEventHandle"},
+ {229, nullptr, "ReadSerialFlash"},
+ {230, nullptr, "WriteSerialFlash"},
+ {231, nullptr, "GetOperationResult"},
+ {232, nullptr, "EnableShipmentMode"},
+ {233, nullptr, "ClearPairingInfo"},
+ {234, nullptr, "GetUniquePadDeviceTypeSetInternal"},
+ {235, nullptr, "EnableAnalogStickPower"},
+ {236, nullptr, "RequestKuinaUartClockCal"},
+ {237, nullptr, "GetKuinaUartClockCal"},
+ {238, nullptr, "SetKuinaUartClockTrim"},
+ {239, nullptr, "KuinaLoopbackTest"},
+ {240, nullptr, "RequestBatteryVoltage"},
+ {241, nullptr, "GetBatteryVoltage"},
+ {242, nullptr, "GetUniquePadPowerInfo"},
+ {243, nullptr, "RebootUniquePad"},
+ {244, nullptr, "RequestKuinaFirmwareVersion"},
+ {245, nullptr, "GetKuinaFirmwareVersion"},
+ {246, nullptr, "GetVidPid"},
+ {247, nullptr, "GetAnalogStickCalibrationValue"},
+ {248, nullptr, "GetUniquePadIdsFull"},
+ {249, nullptr, "ConnectUniquePad"},
+ {250, nullptr, "IsVirtual"},
+ {251, nullptr, "GetAnalogStickModuleParam"},
+ {301, nullptr, "GetAbstractedPadHandles"},
+ {302, nullptr, "GetAbstractedPadState"},
+ {303, nullptr, "GetAbstractedPadsState"},
+ {321, nullptr, "SetAutoPilotVirtualPadState"},
+ {322, nullptr, "UnsetAutoPilotVirtualPadState"},
+ {323, nullptr, "UnsetAllAutoPilotVirtualPadState"},
+ {324, nullptr, "AttachHdlsWorkBuffer"},
+ {325, nullptr, "ReleaseHdlsWorkBuffer"},
+ {326, nullptr, "DumpHdlsNpadAssignmentState"},
+ {327, nullptr, "DumpHdlsStates"},
+ {328, nullptr, "ApplyHdlsNpadAssignmentState"},
+ {329, nullptr, "ApplyHdlsStateList"},
+ {330, nullptr, "AttachHdlsVirtualDevice"},
+ {331, nullptr, "DetachHdlsVirtualDevice"},
+ {332, nullptr, "SetHdlsState"},
+ {350, nullptr, "AddRegisteredDevice"},
+ {400, nullptr, "DisableExternalMcuOnNxDevice"},
+ {401, nullptr, "DisableRailDeviceFiltering"},
+ {402, nullptr, "EnableWiredPairing"},
+ {403, nullptr, "EnableShipmentModeAutoClear"},
+ {404, nullptr, "SetRailEnabled"},
+ {500, nullptr, "SetFactoryInt"},
+ {501, nullptr, "IsFactoryBootEnabled"},
+ {550, nullptr, "SetAnalogStickModelDataTemporarily"},
+ {551, nullptr, "GetAnalogStickModelData"},
+ {552, nullptr, "ResetAnalogStickModelData"},
+ {600, nullptr, "ConvertPadState"},
+ {650, nullptr, "AddButtonPlayData"},
+ {651, nullptr, "StartButtonPlayData"},
+ {652, nullptr, "StopButtonPlayData"},
+ {2000, nullptr, "DeactivateDigitizer"},
+ {2001, nullptr, "SetDigitizerAutoPilotState"},
+ {2002, nullptr, "UnsetDigitizerAutoPilotState"},
+ {2002, nullptr, "ReloadFirmwareDebugSettings"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IHidDebugServer::~IHidDebugServer() = default;
+
+std::shared_ptr<ResourceManager> IHidDebugServer::GetResourceManager() {
+ resource_manager->Initialize();
+ return resource_manager;
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::HID {
+class ResourceManager;
+
+class IHidDebugServer final : public ServiceFramework<IHidDebugServer> {
+public:
+ explicit IHidDebugServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
+ ~IHidDebugServer() override;
+
+private:
+ std::shared_ptr<ResourceManager> GetResourceManager();
+
+ std::shared_ptr<ResourceManager> resource_manager;
+};
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/hid/hid_firmware_settings.h"
+
+namespace Service::HID {
+
+HidFirmwareSettings::HidFirmwareSettings() {
+ LoadSettings(true);
+}
+
+void HidFirmwareSettings::Reload() {
+ LoadSettings(true);
+}
+
+void HidFirmwareSettings::LoadSettings(bool reload_config) {
+ if (is_initalized && !reload_config) {
+ return;
+ }
+
+ // TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values
+
+ is_debug_pad_enabled = true;
+ is_device_managed = true;
+ is_touch_i2c_managed = is_device_managed;
+ is_future_devices_emulated = false;
+ is_mcu_hardware_error_emulated = false;
+ is_rail_enabled = true;
+ is_firmware_update_failure_emulated = false;
+ is_firmware_update_failure = {};
+ is_ble_disabled = false;
+ is_dscale_disabled = false;
+ is_handheld_forced = true;
+ features_per_id_disabled = {};
+ is_touch_firmware_auto_update_disabled = false;
+ is_initalized = true;
+}
+
+bool HidFirmwareSettings::IsDebugPadEnabled() {
+ LoadSettings(false);
+ return is_debug_pad_enabled;
+}
+
+bool HidFirmwareSettings::IsDeviceManaged() {
+ LoadSettings(false);
+ return is_device_managed;
+}
+
+bool HidFirmwareSettings::IsEmulateFutureDevice() {
+ LoadSettings(false);
+ return is_future_devices_emulated;
+}
+
+bool HidFirmwareSettings::IsTouchI2cManaged() {
+ LoadSettings(false);
+ return is_touch_i2c_managed;
+}
+
+bool HidFirmwareSettings::IsHandheldForced() {
+ LoadSettings(false);
+ return is_handheld_forced;
+}
+
+bool HidFirmwareSettings::IsRailEnabled() {
+ LoadSettings(false);
+ return is_rail_enabled;
+}
+
+bool HidFirmwareSettings::IsHardwareErrorEmulated() {
+ LoadSettings(false);
+ return is_mcu_hardware_error_emulated;
+}
+
+bool HidFirmwareSettings::IsBleDisabled() {
+ LoadSettings(false);
+ return is_ble_disabled;
+}
+
+bool HidFirmwareSettings::IsDscaleDisabled() {
+ LoadSettings(false);
+ return is_dscale_disabled;
+}
+
+bool HidFirmwareSettings::IsTouchAutoUpdateDisabled() {
+ LoadSettings(false);
+ return is_touch_firmware_auto_update_disabled;
+}
+
+HidFirmwareSettings::FirmwareSetting HidFirmwareSettings::GetFirmwareUpdateFailure() {
+ LoadSettings(false);
+ return is_firmware_update_failure;
+}
+
+HidFirmwareSettings::FeaturesPerId HidFirmwareSettings::FeaturesDisabledPerId() {
+ LoadSettings(false);
+ return features_per_id_disabled;
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Service::HID {
+
+/// Loads firmware config from nn::settings::fwdbg
+class HidFirmwareSettings {
+public:
+ using FirmwareSetting = std::array<u8, 4>;
+ using FeaturesPerId = std::array<bool, 0xA8>;
+
+ HidFirmwareSettings();
+
+ void Reload();
+ void LoadSettings(bool reload_config);
+
+ bool IsDebugPadEnabled();
+ bool IsDeviceManaged();
+ bool IsEmulateFutureDevice();
+ bool IsTouchI2cManaged();
+ bool IsHandheldForced();
+ bool IsRailEnabled();
+ bool IsHardwareErrorEmulated();
+ bool IsBleDisabled();
+ bool IsDscaleDisabled();
+ bool IsTouchAutoUpdateDisabled();
+
+ FirmwareSetting GetFirmwareUpdateFailure();
+ FeaturesPerId FeaturesDisabledPerId();
+
+private:
+ bool is_initalized{};
+
+ // Debug settings
+ bool is_debug_pad_enabled{};
+ bool is_device_managed{};
+ bool is_touch_i2c_managed{};
+ bool is_future_devices_emulated{};
+ bool is_mcu_hardware_error_emulated{};
+ bool is_rail_enabled{};
+ bool is_firmware_update_failure_emulated{};
+ bool is_ble_disabled{};
+ bool is_dscale_disabled{};
+ bool is_handheld_forced{};
+ bool is_touch_firmware_auto_update_disabled{};
+ FirmwareSetting is_firmware_update_failure{};
+ FeaturesPerId features_per_id_disabled{};
+};
+
+} // 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..9caed6541
--- /dev/null
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -0,0 +1,2440 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <array>
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "common/settings.h"
+#include "core/hid/hid_core.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/kernel/k_transfer_memory.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/hid/errors.h"
+#include "core/hle/service/hid/hid_firmware_settings.h"
+#include "core/hle/service/hid/hid_server.h"
+#include "core/hle/service/hid/resource_manager.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/memory.h"
+
+#include "core/hle/service/hid/controllers/console_sixaxis.h"
+#include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/hle/service/hid/controllers/debug_pad.h"
+#include "core/hle/service/hid/controllers/gesture.h"
+#include "core/hle/service/hid/controllers/keyboard.h"
+#include "core/hle/service/hid/controllers/mouse.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/controllers/palma.h"
+#include "core/hle/service/hid/controllers/stubbed.h"
+#include "core/hle/service/hid/controllers/touchscreen.h"
+#include "core/hle/service/hid/controllers/xpad.h"
+
+namespace Service::HID {
+
+class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
+public:
+ explicit IActiveVibrationDeviceList(Core::System& system_,
+ std::shared_ptr<ResourceManager> resource)
+ : ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void InitializeVibrationDevice(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
+
+ if (resource_manager != nullptr) {
+ resource_manager->GetController<Controller_NPad>(HidController::NPad)
+ .InitializeVibrationDevice(vibration_device_handle);
+ }
+
+ LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
+ vibration_device_handle.npad_type, vibration_device_handle.npad_id,
+ vibration_device_handle.device_index);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ std::shared_ptr<ResourceManager> resource_manager;
+};
+
+IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
+ std::shared_ptr<HidFirmwareSettings> settings)
+ : ServiceFramework{system_, "hid"}, resource_manager{resource}, firmware_settings{settings} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &IHidServer::CreateAppletResource, "CreateAppletResource"},
+ {1, &IHidServer::ActivateDebugPad, "ActivateDebugPad"},
+ {11, &IHidServer::ActivateTouchScreen, "ActivateTouchScreen"},
+ {21, &IHidServer::ActivateMouse, "ActivateMouse"},
+ {26, nullptr, "ActivateDebugMouse"},
+ {31, &IHidServer::ActivateKeyboard, "ActivateKeyboard"},
+ {32, &IHidServer::SendKeyboardLockKeyEvent, "SendKeyboardLockKeyEvent"},
+ {40, &IHidServer::AcquireXpadIdEventHandle, "AcquireXpadIdEventHandle"},
+ {41, &IHidServer::ReleaseXpadIdEventHandle, "ReleaseXpadIdEventHandle"},
+ {51, &IHidServer::ActivateXpad, "ActivateXpad"},
+ {55, &IHidServer::GetXpadIds, "GetXpadIds"},
+ {56, &IHidServer::ActivateJoyXpad, "ActivateJoyXpad"},
+ {58, &IHidServer::GetJoyXpadLifoHandle, "GetJoyXpadLifoHandle"},
+ {59, &IHidServer::GetJoyXpadIds, "GetJoyXpadIds"},
+ {60, &IHidServer::ActivateSixAxisSensor, "ActivateSixAxisSensor"},
+ {61, &IHidServer::DeactivateSixAxisSensor, "DeactivateSixAxisSensor"},
+ {62, &IHidServer::GetSixAxisSensorLifoHandle, "GetSixAxisSensorLifoHandle"},
+ {63, &IHidServer::ActivateJoySixAxisSensor, "ActivateJoySixAxisSensor"},
+ {64, &IHidServer::DeactivateJoySixAxisSensor, "DeactivateJoySixAxisSensor"},
+ {65, &IHidServer::GetJoySixAxisSensorLifoHandle, "GetJoySixAxisSensorLifoHandle"},
+ {66, &IHidServer::StartSixAxisSensor, "StartSixAxisSensor"},
+ {67, &IHidServer::StopSixAxisSensor, "StopSixAxisSensor"},
+ {68, &IHidServer::IsSixAxisSensorFusionEnabled, "IsSixAxisSensorFusionEnabled"},
+ {69, &IHidServer::EnableSixAxisSensorFusion, "EnableSixAxisSensorFusion"},
+ {70, &IHidServer::SetSixAxisSensorFusionParameters, "SetSixAxisSensorFusionParameters"},
+ {71, &IHidServer::GetSixAxisSensorFusionParameters, "GetSixAxisSensorFusionParameters"},
+ {72, &IHidServer::ResetSixAxisSensorFusionParameters, "ResetSixAxisSensorFusionParameters"},
+ {73, nullptr, "SetAccelerometerParameters"},
+ {74, nullptr, "GetAccelerometerParameters"},
+ {75, nullptr, "ResetAccelerometerParameters"},
+ {76, nullptr, "SetAccelerometerPlayMode"},
+ {77, nullptr, "GetAccelerometerPlayMode"},
+ {78, nullptr, "ResetAccelerometerPlayMode"},
+ {79, &IHidServer::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
+ {80, &IHidServer::GetGyroscopeZeroDriftMode, "GetGyroscopeZeroDriftMode"},
+ {81, &IHidServer::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"},
+ {82, &IHidServer::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"},
+ {83, &IHidServer::IsFirmwareUpdateAvailableForSixAxisSensor, "IsFirmwareUpdateAvailableForSixAxisSensor"},
+ {84, &IHidServer::EnableSixAxisSensorUnalteredPassthrough, "EnableSixAxisSensorUnalteredPassthrough"},
+ {85, &IHidServer::IsSixAxisSensorUnalteredPassthroughEnabled, "IsSixAxisSensorUnalteredPassthroughEnabled"},
+ {86, nullptr, "StoreSixAxisSensorCalibrationParameter"},
+ {87, &IHidServer::LoadSixAxisSensorCalibrationParameter, "LoadSixAxisSensorCalibrationParameter"},
+ {88, &IHidServer::GetSixAxisSensorIcInformation, "GetSixAxisSensorIcInformation"},
+ {89, &IHidServer::ResetIsSixAxisSensorDeviceNewlyAssigned, "ResetIsSixAxisSensorDeviceNewlyAssigned"},
+ {91, &IHidServer::ActivateGesture, "ActivateGesture"},
+ {100, &IHidServer::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
+ {101, &IHidServer::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
+ {102, &IHidServer::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
+ {103, &IHidServer::ActivateNpad, "ActivateNpad"},
+ {104, &IHidServer::DeactivateNpad, "DeactivateNpad"},
+ {106, &IHidServer::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
+ {107, &IHidServer::DisconnectNpad, "DisconnectNpad"},
+ {108, &IHidServer::GetPlayerLedPattern, "GetPlayerLedPattern"},
+ {109, &IHidServer::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
+ {120, &IHidServer::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
+ {121, &IHidServer::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
+ {122, &IHidServer::SetNpadJoyAssignmentModeSingleByDefault, "SetNpadJoyAssignmentModeSingleByDefault"},
+ {123, &IHidServer::SetNpadJoyAssignmentModeSingle, "SetNpadJoyAssignmentModeSingle"},
+ {124, &IHidServer::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
+ {125, &IHidServer::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
+ {126, &IHidServer::StartLrAssignmentMode, "StartLrAssignmentMode"},
+ {127, &IHidServer::StopLrAssignmentMode, "StopLrAssignmentMode"},
+ {128, &IHidServer::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
+ {129, &IHidServer::GetNpadHandheldActivationMode, "GetNpadHandheldActivationMode"},
+ {130, &IHidServer::SwapNpadAssignment, "SwapNpadAssignment"},
+ {131, &IHidServer::IsUnintendedHomeButtonInputProtectionEnabled, "IsUnintendedHomeButtonInputProtectionEnabled"},
+ {132, &IHidServer::EnableUnintendedHomeButtonInputProtection, "EnableUnintendedHomeButtonInputProtection"},
+ {133, &IHidServer::SetNpadJoyAssignmentModeSingleWithDestination, "SetNpadJoyAssignmentModeSingleWithDestination"},
+ {134, &IHidServer::SetNpadAnalogStickUseCenterClamp, "SetNpadAnalogStickUseCenterClamp"},
+ {135, &IHidServer::SetNpadCaptureButtonAssignment, "SetNpadCaptureButtonAssignment"},
+ {136, &IHidServer::ClearNpadCaptureButtonAssignment, "ClearNpadCaptureButtonAssignment"},
+ {200, &IHidServer::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
+ {201, &IHidServer::SendVibrationValue, "SendVibrationValue"},
+ {202, &IHidServer::GetActualVibrationValue, "GetActualVibrationValue"},
+ {203, &IHidServer::CreateActiveVibrationDeviceList, "CreateActiveVibrationDeviceList"},
+ {204, &IHidServer::PermitVibration, "PermitVibration"},
+ {205, &IHidServer::IsVibrationPermitted, "IsVibrationPermitted"},
+ {206, &IHidServer::SendVibrationValues, "SendVibrationValues"},
+ {207, &IHidServer::SendVibrationGcErmCommand, "SendVibrationGcErmCommand"},
+ {208, &IHidServer::GetActualVibrationGcErmCommand, "GetActualVibrationGcErmCommand"},
+ {209, &IHidServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
+ {210, &IHidServer::EndPermitVibrationSession, "EndPermitVibrationSession"},
+ {211, &IHidServer::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
+ {212, nullptr, "SendVibrationValueInBool"},
+ {300, &IHidServer::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
+ {301, &IHidServer::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
+ {302, &IHidServer::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
+ {303, &IHidServer::ActivateSevenSixAxisSensor, "ActivateSevenSixAxisSensor"},
+ {304, &IHidServer::StartSevenSixAxisSensor, "StartSevenSixAxisSensor"},
+ {305, &IHidServer::StopSevenSixAxisSensor, "StopSevenSixAxisSensor"},
+ {306, &IHidServer::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"},
+ {307, &IHidServer::FinalizeSevenSixAxisSensor, "FinalizeSevenSixAxisSensor"},
+ {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
+ {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
+ {310, &IHidServer::ResetSevenSixAxisSensorTimestamp, "ResetSevenSixAxisSensorTimestamp"},
+ {400, &IHidServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
+ {401, nullptr, "EnableUsbFullKeyController"},
+ {402, nullptr, "IsUsbFullKeyControllerConnected"},
+ {403, nullptr, "HasBattery"},
+ {404, nullptr, "HasLeftRightBattery"},
+ {405, nullptr, "GetNpadInterfaceType"},
+ {406, nullptr, "GetNpadLeftRightInterfaceType"},
+ {407, nullptr, "GetNpadOfHighestBatteryLevel"},
+ {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
+ {500, &IHidServer::GetPalmaConnectionHandle, "GetPalmaConnectionHandle"},
+ {501, &IHidServer::InitializePalma, "InitializePalma"},
+ {502, &IHidServer::AcquirePalmaOperationCompleteEvent, "AcquirePalmaOperationCompleteEvent"},
+ {503, &IHidServer::GetPalmaOperationInfo, "GetPalmaOperationInfo"},
+ {504, &IHidServer::PlayPalmaActivity, "PlayPalmaActivity"},
+ {505, &IHidServer::SetPalmaFrModeType, "SetPalmaFrModeType"},
+ {506, &IHidServer::ReadPalmaStep, "ReadPalmaStep"},
+ {507, &IHidServer::EnablePalmaStep, "EnablePalmaStep"},
+ {508, &IHidServer::ResetPalmaStep, "ResetPalmaStep"},
+ {509, &IHidServer::ReadPalmaApplicationSection, "ReadPalmaApplicationSection"},
+ {510, &IHidServer::WritePalmaApplicationSection, "WritePalmaApplicationSection"},
+ {511, &IHidServer::ReadPalmaUniqueCode, "ReadPalmaUniqueCode"},
+ {512, &IHidServer::SetPalmaUniqueCodeInvalid, "SetPalmaUniqueCodeInvalid"},
+ {513, &IHidServer::WritePalmaActivityEntry, "WritePalmaActivityEntry"},
+ {514, &IHidServer::WritePalmaRgbLedPatternEntry, "WritePalmaRgbLedPatternEntry"},
+ {515, &IHidServer::WritePalmaWaveEntry, "WritePalmaWaveEntry"},
+ {516, &IHidServer::SetPalmaDataBaseIdentificationVersion, "SetPalmaDataBaseIdentificationVersion"},
+ {517, &IHidServer::GetPalmaDataBaseIdentificationVersion, "GetPalmaDataBaseIdentificationVersion"},
+ {518, &IHidServer::SuspendPalmaFeature, "SuspendPalmaFeature"},
+ {519, &IHidServer::GetPalmaOperationResult, "GetPalmaOperationResult"},
+ {520, &IHidServer::ReadPalmaPlayLog, "ReadPalmaPlayLog"},
+ {521, &IHidServer::ResetPalmaPlayLog, "ResetPalmaPlayLog"},
+ {522, &IHidServer::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
+ {523, &IHidServer::SetIsPalmaPairedConnectable, "SetIsPalmaPairedConnectable"},
+ {524, &IHidServer::PairPalma, "PairPalma"},
+ {525, &IHidServer::SetPalmaBoostMode, "SetPalmaBoostMode"},
+ {526, &IHidServer::CancelWritePalmaWaveEntry, "CancelWritePalmaWaveEntry"},
+ {527, &IHidServer::EnablePalmaBoostMode, "EnablePalmaBoostMode"},
+ {528, &IHidServer::GetPalmaBluetoothAddress, "GetPalmaBluetoothAddress"},
+ {529, &IHidServer::SetDisallowedPalmaConnection, "SetDisallowedPalmaConnection"},
+ {1000, &IHidServer::SetNpadCommunicationMode, "SetNpadCommunicationMode"},
+ {1001, &IHidServer::GetNpadCommunicationMode, "GetNpadCommunicationMode"},
+ {1002, &IHidServer::SetTouchScreenConfiguration, "SetTouchScreenConfiguration"},
+ {1003, &IHidServer::IsFirmwareUpdateNeededForNotification, "IsFirmwareUpdateNeededForNotification"},
+ {2000, nullptr, "ActivateDigitizer"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+IHidServer::~IHidServer() = default;
+
+void IHidServer::CreateAppletResource(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IAppletResource>(system, resource_manager);
+}
+
+void IHidServer::ActivateDebugPad(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ Result result = ResultSuccess;
+ auto& debug_pad =
+ GetResourceManager()->GetController<Controller_DebugPad>(HidController::DebugPad);
+
+ if (!firmware_settings->IsDeviceManaged()) {
+ result = debug_pad.Activate();
+ }
+
+ if (result.IsSuccess()) {
+ result = debug_pad.Activate(applet_resource_user_id);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ActivateTouchScreen(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ Result result = ResultSuccess;
+ auto& touch_screen =
+ GetResourceManager()->GetController<Controller_Touchscreen>(HidController::Touchscreen);
+
+ if (!firmware_settings->IsDeviceManaged()) {
+ result = touch_screen.Activate();
+ }
+
+ if (result.IsSuccess()) {
+ result = touch_screen.Activate(applet_resource_user_id);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ActivateMouse(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ Result result = ResultSuccess;
+ auto& mouse = GetResourceManager()->GetController<Controller_Mouse>(HidController::Mouse);
+
+ if (!firmware_settings->IsDeviceManaged()) {
+ result = mouse.Activate();
+ }
+
+ if (result.IsSuccess()) {
+ result = mouse.Activate(applet_resource_user_id);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ActivateKeyboard(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ Result result = ResultSuccess;
+ auto& keyboard =
+ GetResourceManager()->GetController<Controller_Keyboard>(HidController::Keyboard);
+
+ if (!firmware_settings->IsDeviceManaged()) {
+ result = keyboard.Activate();
+ }
+
+ if (result.IsSuccess()) {
+ result = keyboard.Activate(applet_resource_user_id);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::SendKeyboardLockKeyEvent(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto flags{rp.Pop<u32>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::AcquireXpadIdEventHandle(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ // Handle returned is null here
+}
+
+void IHidServer::ReleaseXpadIdEventHandle(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::ActivateXpad(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ u32 basic_xpad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
+ parameters.basic_xpad_id, parameters.applet_resource_user_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetXpadIds(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
+ // This function has been hardcoded since 10.0.0+
+ const std::array<u32, 4> basic_xpad_id{0, 1, 2, 3};
+ ctx.WriteBuffer(basic_xpad_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push<s64>(basic_xpad_id.size());
+}
+
+void IHidServer::ActivateJoyXpad(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto joy_xpad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetJoyXpadLifoHandle(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto joy_xpad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ // Handle returned is null here
+}
+
+void IHidServer::GetJoyXpadIds(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
+ // This function has been hardcoded since 10.0.0+
+ const s64 basic_xpad_id_count{};
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push(basic_xpad_id_count);
+}
+
+void IHidServer::ActivateSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto joy_xpad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::DeactivateSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto joy_xpad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetSixAxisSensorLifoHandle(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto joy_xpad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::ActivateJoySixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto joy_xpad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::DeactivateJoySixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto joy_xpad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto joy_xpad_id{rp.Pop<u32>()};
+
+ LOG_DEBUG(Service_HID, "called, joy_xpad_id={}", joy_xpad_id);
+
+ // This function has been stubbed since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ // Handle returned is null here
+}
+
+void IHidServer::StartSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, true);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::StopSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.SetSixAxisEnabled(parameters.sixaxis_handle, false);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::IsSixAxisSensorFusionEnabled(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ bool is_enabled{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result =
+ controller.IsSixAxisSensorFusionEnabled(parameters.sixaxis_handle, is_enabled);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(result);
+ rb.Push(is_enabled);
+}
+
+void IHidServer::EnableSixAxisSensorFusion(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool enable_sixaxis_sensor_fusion;
+ INSERT_PADDING_BYTES_NOINIT(3);
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle,
+ parameters.enable_sixaxis_sensor_fusion);
+
+ LOG_DEBUG(Service_HID,
+ "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
+ "device_index={}, applet_resource_user_id={}",
+ parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
+ parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
+ parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::SetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ Core::HID::SixAxisSensorFusionParameters sixaxis_fusion;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result =
+ controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, "
+ "parameter2={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1,
+ parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::GetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ Core::HID::SixAxisSensorFusionParameters fusion_parameters{};
+ const auto& controller =
+ GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result =
+ controller.GetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(result);
+ rb.PushRaw(fusion_parameters);
+}
+
+void IHidServer::ResetSixAxisSensorFusionParameters(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ // Since these parameters are unknown just use what HW outputs
+ const Core::HID::SixAxisSensorFusionParameters fusion_parameters{
+ .parameter1 = 0.03f,
+ .parameter2 = 0.4f,
+ };
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result1 =
+ controller.SetSixAxisFusionParameters(parameters.sixaxis_handle, fusion_parameters);
+ const auto result2 = controller.SetSixAxisFusionEnabled(parameters.sixaxis_handle, true);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ if (result1.IsError()) {
+ rb.Push(result1);
+ return;
+ }
+ rb.Push(result2);
+}
+
+void IHidServer::SetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()};
+ const auto drift_mode{rp.PopEnum<Core::HID::GyroscopeZeroDriftMode>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
+ "applet_resource_user_id={}",
+ sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index,
+ drift_mode, applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::GetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.GetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(result);
+ rb.PushEnum(drift_mode);
+}
+
+void IHidServer::ResetGyroscopeZeroDriftMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ const auto drift_mode{Core::HID::GyroscopeZeroDriftMode::Standard};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::IsSixAxisSensorAtRest(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ bool is_at_rest{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_at_rest);
+}
+
+void IHidServer::IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ bool is_firmware_available{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle,
+ is_firmware_available);
+
+ LOG_WARNING(
+ Service_HID,
+ "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_firmware_available);
+}
+
+void IHidServer::EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool enabled;
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.EnableSixAxisSensorUnalteredPassthrough(
+ parameters.sixaxis_handle, parameters.enabled);
+
+ LOG_DEBUG(Service_HID,
+ "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, "
+ "applet_resource_user_id={}",
+ parameters.enabled, parameters.sixaxis_handle.npad_type,
+ parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
+ parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ bool is_unaltered_sisxaxis_enabled{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled(
+ parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled);
+
+ LOG_DEBUG(
+ Service_HID,
+ "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(result);
+ rb.Push(is_unaltered_sisxaxis_enabled);
+}
+
+void IHidServer::LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ Core::HID::SixAxisSensorCalibrationParameter calibration{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result =
+ controller.LoadSixAxisSensorCalibrationParameter(parameters.sixaxis_handle, calibration);
+
+ LOG_WARNING(
+ Service_HID,
+ "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(calibration);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::GetSixAxisSensorIcInformation(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ Core::HID::SixAxisSensorIcInformation ic_information{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result =
+ controller.GetSixAxisSensorIcInformation(parameters.sixaxis_handle, ic_information);
+
+ LOG_WARNING(
+ Service_HID,
+ "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ if (result.IsSuccess()) {
+ ctx.WriteBuffer(ic_information);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::SixAxisSensorHandle sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result =
+ controller.ResetIsSixAxisSensorDeviceNewlyAssigned(parameters.sixaxis_handle);
+
+ LOG_WARNING(
+ Service_HID,
+ "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
+ parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ActivateGesture(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ u32 basic_gesture_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_INFO(Service_HID, "called, basic_gesture_id={}, applet_resource_user_id={}",
+ parameters.basic_gesture_id, parameters.applet_resource_user_id);
+
+ Result result = ResultSuccess;
+ auto& gesture = GetResourceManager()->GetController<Controller_Gesture>(HidController::Gesture);
+
+ if (!firmware_settings->IsDeviceManaged()) {
+ result = gesture.Activate();
+ }
+
+ if (result.IsSuccess()) {
+ // TODO: Use gesture id here
+ result = gesture.Activate(parameters.applet_resource_user_id);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::SetSupportedNpadStyleSet(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadStyleSet supported_styleset;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SetSupportedStyleSet({parameters.supported_styleset});
+
+ LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}",
+ parameters.supported_styleset, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetSupportedNpadStyleSet(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetSupportedStyleSet()
+ .raw);
+}
+
+void IHidServer::SetSupportedNpadIdType(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ const auto result = GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SetSupportedNpadIdTypes(ctx.ReadBuffer());
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ActivateNpad(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ auto& npad = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+
+ // TODO: npad->SetRevision(applet_resource_user_id, NpadRevision::Revision0);
+ const Result result = npad.Activate(applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::DeactivateNpad(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ // This function does nothing since 10.0.0+
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ u64 unknown;
+ };
+ static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
+ parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
+
+ // Games expect this event to be signaled after calling this function
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SignalStyleSetChangedEvent(parameters.npad_id);
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetStyleSetChangedEvent(parameters.npad_id));
+}
+
+void IHidServer::DisconnectNpad(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ controller.DisconnectNpad(parameters.npad_id);
+
+ LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
+ parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
+
+ Core::HID::LedPattern pattern{0, 0, 0, 0};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.GetLedPattern(npad_id, pattern);
+
+ LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(result);
+ rb.Push(pattern.raw);
+}
+
+void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Controller_NPad::NpadRevision revision;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision,
+ parameters.applet_resource_user_id);
+
+ auto& npad = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+
+ // TODO: npad->SetRevision(applet_resource_user_id, revision);
+ const auto result = npad.Activate(parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+ const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SetHoldType(hold_type);
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
+ applet_resource_user_id, hold_type);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetNpadJoyHoldType(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(
+ GetResourceManager()->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
+}
+
+void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ Core::HID::NpadIdType new_npad_id{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ controller.SetNpadMode(new_npad_id, parameters.npad_id,
+ Controller_NPad::NpadJoyDeviceType::Left,
+ Controller_NPad::NpadJoyAssignmentMode::Single);
+
+ LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
+ parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
+ };
+ static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ Core::HID::NpadIdType new_npad_id{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
+ Controller_NPad::NpadJoyAssignmentMode::Single);
+
+ LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
+ parameters.npad_id, parameters.applet_resource_user_id,
+ parameters.npad_joy_device_type);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ Core::HID::NpadIdType new_npad_id{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ controller.SetNpadMode(new_npad_id, parameters.npad_id, {},
+ Controller_NPad::NpadJoyAssignmentMode::Dual);
+
+ LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
+ parameters.applet_resource_user_id); // Spams a lot when controller applet is open
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::MergeSingleJoyAsDualJoy(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
+ const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
+
+ LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
+ npad_id_1, npad_id_2, applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::StartLrAssignmentMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .StartLRAssignmentMode();
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .StopLRAssignmentMode();
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+ const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SetNpadHandheldActivationMode(activation_mode);
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}",
+ applet_resource_user_id, activation_mode);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetNpadHandheldActivationMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetNpadHandheldActivationMode());
+}
+
+void IHidServer::SwapNpadAssignment(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
+ const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.SwapNpadAssignment(npad_id_1, npad_id_2);
+
+ LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
+ npad_id_1, npad_id_2, applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ bool is_enabled = false;
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result =
+ controller.IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id, is_enabled);
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
+ parameters.npad_id, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(result);
+ rb.Push(is_enabled);
+}
+
+void IHidServer::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool is_enabled;
+ INSERT_PADDING_BYTES_NOINIT(3);
+ Core::HID::NpadIdType npad_id;
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled(
+ parameters.is_enabled, parameters.npad_id);
+
+ LOG_DEBUG(Service_HID,
+ "(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}",
+ parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ Controller_NPad::NpadJoyDeviceType npad_joy_device_type;
+ };
+ static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ Core::HID::NpadIdType new_npad_id{};
+ auto& controller = GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+ const auto is_reassigned =
+ controller.SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
+ Controller_NPad::NpadJoyAssignmentMode::Single);
+
+ LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
+ parameters.npad_id, parameters.applet_resource_user_id,
+ parameters.npad_joy_device_type);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push(is_reassigned);
+ rb.PushEnum(new_npad_id);
+}
+
+void IHidServer::SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool analog_stick_use_center_clamp;
+ INSERT_PADDING_BYTES_NOINIT(7);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SetAnalogStickUseCenterClamp(parameters.analog_stick_use_center_clamp);
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, analog_stick_use_center_clamp={}, applet_resource_user_id={}",
+ parameters.analog_stick_use_center_clamp, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetNpadCaptureButtonAssignment(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadStyleSet npad_styleset;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ Core::HID::NpadButton button;
+ };
+ static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, npad_styleset={}, applet_resource_user_id={}, button={}",
+ parameters.npad_styleset, parameters.applet_resource_user_id, parameters.button);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
+ applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
+ const auto& controller =
+ GetResourceManager()->GetController<Controller_NPad>(HidController::NPad);
+
+ Core::HID::VibrationDeviceInfo vibration_device_info;
+ bool check_device_index = false;
+
+ switch (vibration_device_handle.npad_type) {
+ case Core::HID::NpadStyleIndex::ProController:
+ case Core::HID::NpadStyleIndex::Handheld:
+ case Core::HID::NpadStyleIndex::JoyconDual:
+ case Core::HID::NpadStyleIndex::JoyconLeft:
+ case Core::HID::NpadStyleIndex::JoyconRight:
+ vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
+ check_device_index = true;
+ break;
+ case Core::HID::NpadStyleIndex::GameCube:
+ vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
+ break;
+ case Core::HID::NpadStyleIndex::N64:
+ vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
+ break;
+ default:
+ vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
+ break;
+ }
+
+ vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
+ if (check_device_index) {
+ switch (vibration_device_handle.device_index) {
+ case Core::HID::DeviceIndex::Left:
+ vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
+ break;
+ case Core::HID::DeviceIndex::Right:
+ vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
+ break;
+ case Core::HID::DeviceIndex::None:
+ default:
+ ASSERT_MSG(false, "DeviceIndex should never be None!");
+ break;
+ }
+ }
+
+ LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
+ vibration_device_info.type, vibration_device_info.position);
+
+ const auto result = controller.IsDeviceHandleValid(vibration_device_handle);
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(vibration_device_info);
+}
+
+void IHidServer::SendVibrationValue(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::VibrationDeviceHandle vibration_device_handle;
+ Core::HID::VibrationValue vibration_value;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .VibrateController(parameters.vibration_device_handle, parameters.vibration_value);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.vibration_device_handle.npad_type,
+ parameters.vibration_device_handle.npad_id,
+ parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::VibrationDeviceHandle vibration_device_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.vibration_device_handle.npad_type,
+ parameters.vibration_device_handle.npad_id,
+ parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetLastVibration(parameters.vibration_device_handle));
+}
+
+void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IActiveVibrationDeviceList>(system, GetResourceManager());
+}
+
+void IHidServer::PermitVibration(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto can_vibrate{rp.Pop<bool>()};
+
+ // nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value
+ // by converting it to a bool
+ Settings::values.vibration_enabled.SetValue(can_vibrate);
+
+ LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::IsVibrationPermitted(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
+ // nnSDK checks if a float is greater than zero. We return the bool we stored earlier
+ const auto is_enabled = Settings::values.vibration_enabled.GetValue();
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_enabled);
+}
+
+void IHidServer::SendVibrationValues(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ const auto handle_data = ctx.ReadBuffer(0);
+ const auto handle_count = ctx.GetReadBufferNumElements<Core::HID::VibrationDeviceHandle>(0);
+ const auto vibration_data = ctx.ReadBuffer(1);
+ const auto vibration_count = ctx.GetReadBufferNumElements<Core::HID::VibrationValue>(1);
+
+ auto vibration_device_handles =
+ std::span(reinterpret_cast<const Core::HID::VibrationDeviceHandle*>(handle_data.data()),
+ handle_count);
+ auto vibration_values = std::span(
+ reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .VibrateControllers(vibration_device_handles, vibration_values);
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::VibrationDeviceHandle vibration_device_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ Core::HID::VibrationGcErmCommand gc_erm_command;
+ };
+ static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ /**
+ * Note: This uses yuzu-specific behavior such that the StopHard command produces
+ * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below,
+ * in order to differentiate between Stop and StopHard commands.
+ * This is done to reuse the controller vibration functions made for regular controllers.
+ */
+ const auto vibration_value = [parameters] {
+ switch (parameters.gc_erm_command) {
+ case Core::HID::VibrationGcErmCommand::Stop:
+ return Core::HID::VibrationValue{
+ .low_amplitude = 0.0f,
+ .low_frequency = 160.0f,
+ .high_amplitude = 0.0f,
+ .high_frequency = 320.0f,
+ };
+ case Core::HID::VibrationGcErmCommand::Start:
+ return Core::HID::VibrationValue{
+ .low_amplitude = 1.0f,
+ .low_frequency = 160.0f,
+ .high_amplitude = 1.0f,
+ .high_frequency = 320.0f,
+ };
+ case Core::HID::VibrationGcErmCommand::StopHard:
+ return Core::HID::VibrationValue{
+ .low_amplitude = 0.0f,
+ .low_frequency = 0.0f,
+ .high_amplitude = 0.0f,
+ .high_frequency = 0.0f,
+ };
+ default:
+ return Core::HID::DEFAULT_VIBRATION_VALUE;
+ }
+ }();
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .VibrateController(parameters.vibration_device_handle, vibration_value);
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
+ "gc_erm_command={}",
+ parameters.vibration_device_handle.npad_type,
+ parameters.vibration_device_handle.npad_id,
+ parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
+ parameters.gc_erm_command);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::VibrationDeviceHandle vibration_device_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ const auto last_vibration = GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetLastVibration(parameters.vibration_device_handle);
+
+ const auto gc_erm_command = [last_vibration] {
+ if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
+ return Core::HID::VibrationGcErmCommand::Start;
+ }
+
+ /**
+ * Note: This uses yuzu-specific behavior such that the StopHard command produces
+ * vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function
+ * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
+ * This is done to reuse the controller vibration functions made for regular controllers.
+ */
+ if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) {
+ return Core::HID::VibrationGcErmCommand::StopHard;
+ }
+
+ return Core::HID::VibrationGcErmCommand::Stop;
+ }();
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.vibration_device_handle.npad_type,
+ parameters.vibration_device_handle.npad_id,
+ parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(gc_erm_command);
+}
+
+void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SetPermitVibrationSession(true);
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) {
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SetPermitVibrationSession(false);
+
+ LOG_DEBUG(Service_HID, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::VibrationDeviceHandle vibration_device_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_DEBUG(Service_HID,
+ "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
+ parameters.vibration_device_handle.npad_type,
+ parameters.vibration_device_handle.npad_id,
+ parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .IsVibrationDeviceMounted(parameters.vibration_device_handle));
+}
+
+void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ Result result = ResultSuccess;
+ auto console_sixaxis = GetResourceManager()->GetController<Controller_ConsoleSixAxis>(
+ HidController::ConsoleSixAxisSensor);
+
+ if (!firmware_settings->IsDeviceManaged()) {
+ result = console_sixaxis.Activate();
+ }
+
+ if (result.IsSuccess()) {
+ result = console_sixaxis.Activate(applet_resource_user_id);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::StartConsoleSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
+ parameters.console_sixaxis_handle.unknown_1,
+ parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::StopConsoleSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
+ parameters.console_sixaxis_handle.unknown_1,
+ parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::ActivateSevenSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ Result result = ResultSuccess;
+ auto console_sixaxis = GetResourceManager()->GetController<Controller_ConsoleSixAxis>(
+ HidController::ConsoleSixAxisSensor);
+
+ if (!firmware_settings->IsDeviceManaged()) {
+ result = console_sixaxis.Activate();
+ }
+
+ if (result.IsSuccess()) {
+ console_sixaxis.Activate(applet_resource_user_id);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::StartSevenSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
+ applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::StopSevenSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
+ applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::InitializeSevenSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+ const auto t_mem_1_size{rp.Pop<u64>()};
+ const auto t_mem_2_size{rp.Pop<u64>()};
+ const auto t_mem_1_handle{ctx.GetCopyHandle(0)};
+ const auto t_mem_2_handle{ctx.GetCopyHandle(1)};
+
+ ASSERT_MSG(t_mem_1_size == 0x1000, "t_mem_1_size is not 0x1000 bytes");
+ ASSERT_MSG(t_mem_2_size == 0x7F000, "t_mem_2_size is not 0x7F000 bytes");
+
+ auto t_mem_1 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_1_handle);
+
+ if (t_mem_1.IsNull()) {
+ LOG_ERROR(Service_HID, "t_mem_1 is a nullptr for handle=0x{:08X}", t_mem_1_handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ auto t_mem_2 = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_2_handle);
+
+ if (t_mem_2.IsNull()) {
+ LOG_ERROR(Service_HID, "t_mem_2 is a nullptr for handle=0x{:08X}", t_mem_2_handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ ASSERT_MSG(t_mem_1->GetSize() == 0x1000, "t_mem_1 has incorrect size");
+ ASSERT_MSG(t_mem_2->GetSize() == 0x7F000, "t_mem_2 has incorrect size");
+
+ // Activate console six axis controller
+ GetResourceManager()
+ ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
+ .Activate();
+
+ GetResourceManager()
+ ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
+ .SetTransferMemoryAddress(t_mem_1->GetSourceAddress());
+
+ LOG_WARNING(Service_HID,
+ "called, t_mem_1_handle=0x{:08X}, t_mem_2_handle=0x{:08X}, "
+ "applet_resource_user_id={}",
+ t_mem_1_handle, t_mem_2_handle, applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::FinalizeSevenSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
+ applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ GetResourceManager()
+ ->GetController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor)
+ .ResetTimestamp();
+
+ LOG_WARNING(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(false);
+}
+
+void IHidServer::GetPalmaConnectionHandle(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ Core::HID::NpadIdType npad_id;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
+ parameters.npad_id, parameters.applet_resource_user_id);
+
+ Controller_Palma::PalmaConnectionHandle handle;
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+ const auto result = controller.GetPalmaConnectionHandle(parameters.npad_id, handle);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(result);
+ rb.PushRaw(handle);
+}
+
+void IHidServer::InitializePalma(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+ const auto result = controller.InitializePalma(connection_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(controller.AcquirePalmaOperationCompleteEvent(connection_handle));
+}
+
+void IHidServer::GetPalmaOperationInfo(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ Controller_Palma::PalmaOperationType operation_type;
+ Controller_Palma::PalmaOperationData data;
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+ const auto result = controller.GetPalmaOperationInfo(connection_handle, operation_type, data);
+
+ if (result.IsError()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ }
+
+ ctx.WriteBuffer(data);
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(result);
+ rb.Push(static_cast<u64>(operation_type));
+}
+
+void IHidServer::PlayPalmaActivity(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+ const auto palma_activity{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, palma_activity={}",
+ connection_handle.npad_id, palma_activity);
+
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+ const auto result = controller.PlayPalmaActivity(connection_handle, palma_activity);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::SetPalmaFrModeType(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+ const auto fr_mode{rp.PopEnum<Controller_Palma::PalmaFrModeType>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, fr_mode={}",
+ connection_handle.npad_id, fr_mode);
+
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+ const auto result = controller.SetPalmaFrModeType(connection_handle, fr_mode);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ReadPalmaStep(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+ const auto result = controller.ReadPalmaStep(connection_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::EnablePalmaStep(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool is_enabled;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ Controller_Palma::PalmaConnectionHandle connection_handle;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, is_enabled={}",
+ parameters.connection_handle.npad_id, parameters.is_enabled);
+
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+ const auto result =
+ controller.EnablePalmaStep(parameters.connection_handle, parameters.is_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ResetPalmaStep(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ auto& controller = GetResourceManager()->GetController<Controller_Palma>(HidController::Palma);
+ const auto result = controller.ResetPalmaStep(connection_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ReadPalmaApplicationSection(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::WritePalmaApplicationSection(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::ReadPalmaUniqueCode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .ReadPalmaUniqueCode(connection_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetPalmaUniqueCodeInvalid(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .SetPalmaUniqueCodeInvalid(connection_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::WritePalmaActivityEntry(HLERequestContext& ctx) {
+ LOG_CRITICAL(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::WritePalmaRgbLedPatternEntry(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+ const auto unknown{rp.Pop<u64>()};
+
+ [[maybe_unused]] const auto buffer = ctx.ReadBuffer();
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, unknown={}",
+ connection_handle.npad_id, unknown);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .WritePalmaRgbLedPatternEntry(connection_handle, unknown);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::WritePalmaWaveEntry(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+ const auto wave_set{rp.PopEnum<Controller_Palma::PalmaWaveSet>()};
+ const auto unknown{rp.Pop<u64>()};
+ const auto t_mem_size{rp.Pop<u64>()};
+ const auto t_mem_handle{ctx.GetCopyHandle(0)};
+ const auto size{rp.Pop<u64>()};
+
+ ASSERT_MSG(t_mem_size == 0x3000, "t_mem_size is not 0x3000 bytes");
+
+ auto t_mem = system.ApplicationProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(
+ t_mem_handle);
+
+ if (t_mem.IsNull()) {
+ LOG_ERROR(Service_HID, "t_mem is a nullptr for handle=0x{:08X}", t_mem_handle);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ ASSERT_MSG(t_mem->GetSize() == 0x3000, "t_mem has incorrect size");
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, connection_handle={}, wave_set={}, unknown={}, "
+ "t_mem_handle=0x{:08X}, t_mem_size={}, size={}",
+ connection_handle.npad_id, wave_set, unknown, t_mem_handle, t_mem_size, size);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .WritePalmaWaveEntry(connection_handle, wave_set, t_mem->GetSourceAddress(), t_mem_size);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ s32 database_id_version;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ Controller_Palma::PalmaConnectionHandle connection_handle;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}, database_id_version={}",
+ parameters.connection_handle.npad_id, parameters.database_id_version);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .SetPalmaDataBaseIdentificationVersion(parameters.connection_handle,
+ parameters.database_id_version);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .GetPalmaDataBaseIdentificationVersion(connection_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SuspendPalmaFeature(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetPalmaOperationResult(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ const auto result = GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .GetPalmaOperationResult(connection_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+}
+
+void IHidServer::ReadPalmaPlayLog(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::ResetPalmaPlayLog(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetIsPalmaAllConnectable(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool is_palma_all_connectable;
+ INSERT_PADDING_BYTES_NOINIT(7);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_HID,
+ "(STUBBED) called, is_palma_all_connectable={},applet_resource_user_id={}",
+ parameters.is_palma_all_connectable, parameters.applet_resource_user_id);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .SetIsPalmaAllConnectable(parameters.is_palma_all_connectable);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetIsPalmaPairedConnectable(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::PairPalma(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto connection_handle{rp.PopRaw<Controller_Palma::PalmaConnectionHandle>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, connection_handle={}", connection_handle.npad_id);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .PairPalma(connection_handle);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetPalmaBoostMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto palma_boost_mode{rp.Pop<bool>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode);
+
+ GetResourceManager()
+ ->GetController<Controller_Palma>(HidController::Palma)
+ .SetPalmaBoostMode(palma_boost_mode);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::CancelWritePalmaWaveEntry(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::EnablePalmaBoostMode(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetPalmaBluetoothAddress(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+ const auto communication_mode{rp.PopEnum<Controller_NPad::NpadCommunicationMode>()};
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .SetNpadCommunicationMode(communication_mode);
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, communication_mode={}",
+ applet_resource_user_id, communication_mode);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::GetNpadCommunicationMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetNpadCommunicationMode());
+}
+
+void IHidServer::SetTouchScreenConfiguration(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto touchscreen_mode{rp.PopRaw<Core::HID::TouchScreenConfigurationForNx>()};
+ const auto applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, touchscreen_mode={}, applet_resource_user_id={}",
+ touchscreen_mode.mode, applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidServer::IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ s32 unknown;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}",
+ parameters.unknown, parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(false);
+}
+
+std::shared_ptr<ResourceManager> IHidServer::GetResourceManager() {
+ resource_manager->Initialize();
+ return resource_manager;
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Core {
+class System;
+}
+
+namespace Service::HID {
+class ResourceManager;
+class HidFirmwareSettings;
+
+class IHidServer final : public ServiceFramework<IHidServer> {
+public:
+ explicit IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> resource,
+ std::shared_ptr<HidFirmwareSettings> settings);
+ ~IHidServer() override;
+
+ std::shared_ptr<ResourceManager> GetResourceManager();
+
+private:
+ void CreateAppletResource(HLERequestContext& ctx);
+ void ActivateDebugPad(HLERequestContext& ctx);
+ void ActivateTouchScreen(HLERequestContext& ctx);
+ void ActivateMouse(HLERequestContext& ctx);
+ void ActivateKeyboard(HLERequestContext& ctx);
+ void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
+ void AcquireXpadIdEventHandle(HLERequestContext& ctx);
+ void ReleaseXpadIdEventHandle(HLERequestContext& ctx);
+ void ActivateXpad(HLERequestContext& ctx);
+ void GetXpadIds(HLERequestContext& ctx);
+ void ActivateJoyXpad(HLERequestContext& ctx);
+ void GetJoyXpadLifoHandle(HLERequestContext& ctx);
+ void GetJoyXpadIds(HLERequestContext& ctx);
+ void ActivateSixAxisSensor(HLERequestContext& ctx);
+ void DeactivateSixAxisSensor(HLERequestContext& ctx);
+ void GetSixAxisSensorLifoHandle(HLERequestContext& ctx);
+ void ActivateJoySixAxisSensor(HLERequestContext& ctx);
+ void DeactivateJoySixAxisSensor(HLERequestContext& ctx);
+ void GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx);
+ void StartSixAxisSensor(HLERequestContext& ctx);
+ void StopSixAxisSensor(HLERequestContext& ctx);
+ void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
+ void EnableSixAxisSensorFusion(HLERequestContext& ctx);
+ void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
+ void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
+ void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
+ void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
+ void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
+ void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
+ void IsSixAxisSensorAtRest(HLERequestContext& ctx);
+ void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
+ void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
+ void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
+ void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
+ void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
+ void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
+ void ActivateGesture(HLERequestContext& ctx);
+ void SetSupportedNpadStyleSet(HLERequestContext& ctx);
+ void GetSupportedNpadStyleSet(HLERequestContext& ctx);
+ void SetSupportedNpadIdType(HLERequestContext& ctx);
+ void ActivateNpad(HLERequestContext& ctx);
+ void DeactivateNpad(HLERequestContext& ctx);
+ void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
+ void DisconnectNpad(HLERequestContext& ctx);
+ void GetPlayerLedPattern(HLERequestContext& ctx);
+ void ActivateNpadWithRevision(HLERequestContext& ctx);
+ void SetNpadJoyHoldType(HLERequestContext& ctx);
+ void GetNpadJoyHoldType(HLERequestContext& ctx);
+ void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
+ void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
+ void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
+ void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
+ void StartLrAssignmentMode(HLERequestContext& ctx);
+ void StopLrAssignmentMode(HLERequestContext& ctx);
+ void SetNpadHandheldActivationMode(HLERequestContext& ctx);
+ void GetNpadHandheldActivationMode(HLERequestContext& ctx);
+ void SwapNpadAssignment(HLERequestContext& ctx);
+ void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
+ void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
+ void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
+ void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
+ void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
+ void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
+ void GetVibrationDeviceInfo(HLERequestContext& ctx);
+ void SendVibrationValue(HLERequestContext& ctx);
+ void GetActualVibrationValue(HLERequestContext& ctx);
+ void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
+ void PermitVibration(HLERequestContext& ctx);
+ void IsVibrationPermitted(HLERequestContext& ctx);
+ void SendVibrationValues(HLERequestContext& ctx);
+ void SendVibrationGcErmCommand(HLERequestContext& ctx);
+ void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
+ void BeginPermitVibrationSession(HLERequestContext& ctx);
+ void EndPermitVibrationSession(HLERequestContext& ctx);
+ void IsVibrationDeviceMounted(HLERequestContext& ctx);
+ void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
+ void StartConsoleSixAxisSensor(HLERequestContext& ctx);
+ void StopConsoleSixAxisSensor(HLERequestContext& ctx);
+ void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
+ void StartSevenSixAxisSensor(HLERequestContext& ctx);
+ void StopSevenSixAxisSensor(HLERequestContext& ctx);
+ void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
+ void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
+ void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
+ void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
+ void GetPalmaConnectionHandle(HLERequestContext& ctx);
+ void InitializePalma(HLERequestContext& ctx);
+ void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
+ void GetPalmaOperationInfo(HLERequestContext& ctx);
+ void PlayPalmaActivity(HLERequestContext& ctx);
+ void SetPalmaFrModeType(HLERequestContext& ctx);
+ void ReadPalmaStep(HLERequestContext& ctx);
+ void EnablePalmaStep(HLERequestContext& ctx);
+ void ResetPalmaStep(HLERequestContext& ctx);
+ void ReadPalmaApplicationSection(HLERequestContext& ctx);
+ void WritePalmaApplicationSection(HLERequestContext& ctx);
+ void ReadPalmaUniqueCode(HLERequestContext& ctx);
+ void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
+ void WritePalmaActivityEntry(HLERequestContext& ctx);
+ void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
+ void WritePalmaWaveEntry(HLERequestContext& ctx);
+ void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
+ void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
+ void SuspendPalmaFeature(HLERequestContext& ctx);
+ void GetPalmaOperationResult(HLERequestContext& ctx);
+ void ReadPalmaPlayLog(HLERequestContext& ctx);
+ void ResetPalmaPlayLog(HLERequestContext& ctx);
+ void SetIsPalmaAllConnectable(HLERequestContext& ctx);
+ void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
+ void PairPalma(HLERequestContext& ctx);
+ void SetPalmaBoostMode(HLERequestContext& ctx);
+ void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
+ void EnablePalmaBoostMode(HLERequestContext& ctx);
+ void GetPalmaBluetoothAddress(HLERequestContext& ctx);
+ void SetDisallowedPalmaConnection(HLERequestContext& ctx);
+ void SetNpadCommunicationMode(HLERequestContext& ctx);
+ void GetNpadCommunicationMode(HLERequestContext& ctx);
+ void SetTouchScreenConfiguration(HLERequestContext& ctx);
+ void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
+
+ std::shared_ptr<ResourceManager> resource_manager;
+ std::shared_ptr<HidFirmwareSettings> firmware_settings;
+};
+
+} // 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..6f1902ee5
--- /dev/null
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -0,0 +1,551 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hid/hid_core.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/controllers/touchscreen.h"
+#include "core/hle/service/hid/errors.h"
+#include "core/hle/service/hid/hid_system_server.h"
+#include "core/hle/service/hid/resource_manager.h"
+#include "core/hle/service/ipc_helpers.h"
+
+namespace Service::HID {
+
+IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource)
+ : ServiceFramework{system_, "hid:sys"}, service_context{system_, service_name},
+ resource_manager{resource} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {31, nullptr, "SendKeyboardLockKeyEvent"},
+ {101, nullptr, "AcquireHomeButtonEventHandle"},
+ {111, nullptr, "ActivateHomeButton"},
+ {121, nullptr, "AcquireSleepButtonEventHandle"},
+ {131, nullptr, "ActivateSleepButton"},
+ {141, nullptr, "AcquireCaptureButtonEventHandle"},
+ {151, nullptr, "ActivateCaptureButton"},
+ {161, nullptr, "GetPlatformConfig"},
+ {210, nullptr, "AcquireNfcDeviceUpdateEventHandle"},
+ {211, nullptr, "GetNpadsWithNfc"},
+ {212, nullptr, "AcquireNfcActivateEventHandle"},
+ {213, nullptr, "ActivateNfc"},
+ {214, nullptr, "GetXcdHandleForNpadWithNfc"},
+ {215, nullptr, "IsNfcActivated"},
+ {230, nullptr, "AcquireIrSensorEventHandle"},
+ {231, nullptr, "ActivateIrSensor"},
+ {232, nullptr, "GetIrSensorState"},
+ {233, nullptr, "GetXcdHandleForNpadWithIrSensor"},
+ {301, nullptr, "ActivateNpadSystem"},
+ {303, &IHidSystemServer::ApplyNpadSystemCommonPolicy, "ApplyNpadSystemCommonPolicy"},
+ {304, &IHidSystemServer::EnableAssigningSingleOnSlSrPress, "EnableAssigningSingleOnSlSrPress"},
+ {305, &IHidSystemServer::DisableAssigningSingleOnSlSrPress, "DisableAssigningSingleOnSlSrPress"},
+ {306, &IHidSystemServer::GetLastActiveNpad, "GetLastActiveNpad"},
+ {307, nullptr, "GetNpadSystemExtStyle"},
+ {308, &IHidSystemServer::ApplyNpadSystemCommonPolicyFull, "ApplyNpadSystemCommonPolicyFull"},
+ {309, &IHidSystemServer::GetNpadFullKeyGripColor, "GetNpadFullKeyGripColor"},
+ {310, &IHidSystemServer::GetMaskedSupportedNpadStyleSet, "GetMaskedSupportedNpadStyleSet"},
+ {311, nullptr, "SetNpadPlayerLedBlinkingDevice"},
+ {312, &IHidSystemServer::SetSupportedNpadStyleSetAll, "SetSupportedNpadStyleSetAll"},
+ {313, nullptr, "GetNpadCaptureButtonAssignment"},
+ {314, nullptr, "GetAppletFooterUiType"},
+ {315, &IHidSystemServer::GetAppletDetailedUiType, "GetAppletDetailedUiType"},
+ {316, &IHidSystemServer::GetNpadInterfaceType, "GetNpadInterfaceType"},
+ {317, &IHidSystemServer::GetNpadLeftRightInterfaceType, "GetNpadLeftRightInterfaceType"},
+ {318, &IHidSystemServer::HasBattery, "HasBattery"},
+ {319, &IHidSystemServer::HasLeftRightBattery, "HasLeftRightBattery"},
+ {321, &IHidSystemServer::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
+ {322, &IHidSystemServer::GetIrSensorState, "GetIrSensorState"},
+ {323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
+ {324, nullptr, "GetUniquePadButtonSet"},
+ {325, nullptr, "GetUniquePadColor"},
+ {326, nullptr, "GetUniquePadAppletDetailedUiType"},
+ {327, nullptr, "GetAbstractedPadIdDataFromNpad"},
+ {328, nullptr, "AttachAbstractedPadToNpad"},
+ {329, nullptr, "DetachAbstractedPadAll"},
+ {330, nullptr, "CheckAbstractedPadConnection"},
+ {500, nullptr, "SetAppletResourceUserId"},
+ {501, nullptr, "RegisterAppletResourceUserId"},
+ {502, nullptr, "UnregisterAppletResourceUserId"},
+ {503, nullptr, "EnableAppletToGetInput"},
+ {504, nullptr, "SetAruidValidForVibration"},
+ {505, nullptr, "EnableAppletToGetSixAxisSensor"},
+ {506, nullptr, "EnableAppletToGetPadInput"},
+ {507, nullptr, "EnableAppletToGetTouchScreen"},
+ {510, nullptr, "SetVibrationMasterVolume"},
+ {511, nullptr, "GetVibrationMasterVolume"},
+ {512, nullptr, "BeginPermitVibrationSession"},
+ {513, nullptr, "EndPermitVibrationSession"},
+ {514, nullptr, "Unknown514"},
+ {520, nullptr, "EnableHandheldHids"},
+ {521, nullptr, "DisableHandheldHids"},
+ {522, nullptr, "SetJoyConRailEnabled"},
+ {523, nullptr, "IsJoyConRailEnabled"},
+ {524, nullptr, "IsHandheldHidsEnabled"},
+ {525, nullptr, "IsJoyConAttachedOnAllRail"},
+ {540, nullptr, "AcquirePlayReportControllerUsageUpdateEvent"},
+ {541, nullptr, "GetPlayReportControllerUsages"},
+ {542, nullptr, "AcquirePlayReportRegisteredDeviceUpdateEvent"},
+ {543, nullptr, "GetRegisteredDevicesOld"},
+ {544, &IHidSystemServer::AcquireConnectionTriggerTimeoutEvent, "AcquireConnectionTriggerTimeoutEvent"},
+ {545, nullptr, "SendConnectionTrigger"},
+ {546, &IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport, "AcquireDeviceRegisteredEventForControllerSupport"},
+ {547, nullptr, "GetAllowedBluetoothLinksCount"},
+ {548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
+ {549, nullptr, "GetConnectableRegisteredDevices"},
+ {700, nullptr, "ActivateUniquePad"},
+ {702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
+ {703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
+ {751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
+ {800, nullptr, "ListSixAxisSensorHandles"},
+ {801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
+ {802, nullptr, "ResetSixAxisSensorCalibrationValues"},
+ {803, nullptr, "StartSixAxisSensorUserCalibration"},
+ {804, nullptr, "CancelSixAxisSensorUserCalibration"},
+ {805, nullptr, "GetUniquePadBluetoothAddress"},
+ {806, nullptr, "DisconnectUniquePad"},
+ {807, nullptr, "GetUniquePadType"},
+ {808, nullptr, "GetUniquePadInterface"},
+ {809, nullptr, "GetUniquePadSerialNumber"},
+ {810, nullptr, "GetUniquePadControllerNumber"},
+ {811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
+ {812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
+ {821, nullptr, "StartAnalogStickManualCalibration"},
+ {822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
+ {823, nullptr, "CancelAnalogStickManualCalibration"},
+ {824, nullptr, "ResetAnalogStickManualCalibration"},
+ {825, nullptr, "GetAnalogStickState"},
+ {826, nullptr, "GetAnalogStickManualCalibrationStage"},
+ {827, nullptr, "IsAnalogStickButtonPressed"},
+ {828, nullptr, "IsAnalogStickInReleasePosition"},
+ {829, nullptr, "IsAnalogStickInCircumference"},
+ {830, nullptr, "SetNotificationLedPattern"},
+ {831, nullptr, "SetNotificationLedPatternWithTimeout"},
+ {832, nullptr, "PrepareHidsForNotificationWake"},
+ {850, &IHidSystemServer::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"},
+ {851, nullptr, "EnableUsbFullKeyController"},
+ {852, nullptr, "IsUsbConnected"},
+ {870, &IHidSystemServer::IsHandheldButtonPressedOnConsoleMode, "IsHandheldButtonPressedOnConsoleMode"},
+ {900, nullptr, "ActivateInputDetector"},
+ {901, nullptr, "NotifyInputDetector"},
+ {1000, &IHidSystemServer::InitializeFirmwareUpdate, "InitializeFirmwareUpdate"},
+ {1001, nullptr, "GetFirmwareVersion"},
+ {1002, nullptr, "GetAvailableFirmwareVersion"},
+ {1003, nullptr, "IsFirmwareUpdateAvailable"},
+ {1004, nullptr, "CheckFirmwareUpdateRequired"},
+ {1005, nullptr, "StartFirmwareUpdate"},
+ {1006, nullptr, "AbortFirmwareUpdate"},
+ {1007, nullptr, "GetFirmwareUpdateState"},
+ {1008, nullptr, "ActivateAudioControl"},
+ {1009, nullptr, "AcquireAudioControlEventHandle"},
+ {1010, nullptr, "GetAudioControlStates"},
+ {1011, nullptr, "DeactivateAudioControl"},
+ {1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
+ {1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
+ {1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
+ {1053, nullptr, "GetSixAxisSensorAccurateUserCalibrationState"},
+ {1100, nullptr, "GetHidbusSystemServiceObject"},
+ {1120, nullptr, "SetFirmwareHotfixUpdateSkipEnabled"},
+ {1130, nullptr, "InitializeUsbFirmwareUpdate"},
+ {1131, nullptr, "FinalizeUsbFirmwareUpdate"},
+ {1132, nullptr, "CheckUsbFirmwareUpdateRequired"},
+ {1133, nullptr, "StartUsbFirmwareUpdate"},
+ {1134, nullptr, "GetUsbFirmwareUpdateState"},
+ {1135, &IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory, "InitializeUsbFirmwareUpdateWithoutMemory"},
+ {1150, nullptr, "SetTouchScreenMagnification"},
+ {1151, nullptr, "GetTouchScreenFirmwareVersion"},
+ {1152, nullptr, "SetTouchScreenDefaultConfiguration"},
+ {1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
+ {1154, nullptr, "IsFirmwareAvailableForNotification"},
+ {1155, nullptr, "SetForceHandheldStyleVibration"},
+ {1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
+ {1157, nullptr, "CancelConnectionTrigger"},
+ {1200, nullptr, "IsButtonConfigSupported"},
+ {1201, nullptr, "IsButtonConfigEmbeddedSupported"},
+ {1202, nullptr, "DeleteButtonConfig"},
+ {1203, nullptr, "DeleteButtonConfigEmbedded"},
+ {1204, nullptr, "SetButtonConfigEnabled"},
+ {1205, nullptr, "SetButtonConfigEmbeddedEnabled"},
+ {1206, nullptr, "IsButtonConfigEnabled"},
+ {1207, nullptr, "IsButtonConfigEmbeddedEnabled"},
+ {1208, nullptr, "SetButtonConfigEmbedded"},
+ {1209, nullptr, "SetButtonConfigFull"},
+ {1210, nullptr, "SetButtonConfigLeft"},
+ {1211, nullptr, "SetButtonConfigRight"},
+ {1212, nullptr, "GetButtonConfigEmbedded"},
+ {1213, nullptr, "GetButtonConfigFull"},
+ {1214, nullptr, "GetButtonConfigLeft"},
+ {1215, nullptr, "GetButtonConfigRight"},
+ {1250, nullptr, "IsCustomButtonConfigSupported"},
+ {1251, nullptr, "IsDefaultButtonConfigEmbedded"},
+ {1252, nullptr, "IsDefaultButtonConfigFull"},
+ {1253, nullptr, "IsDefaultButtonConfigLeft"},
+ {1254, nullptr, "IsDefaultButtonConfigRight"},
+ {1255, nullptr, "IsButtonConfigStorageEmbeddedEmpty"},
+ {1256, nullptr, "IsButtonConfigStorageFullEmpty"},
+ {1257, nullptr, "IsButtonConfigStorageLeftEmpty"},
+ {1258, nullptr, "IsButtonConfigStorageRightEmpty"},
+ {1259, nullptr, "GetButtonConfigStorageEmbeddedDeprecated"},
+ {1260, nullptr, "GetButtonConfigStorageFullDeprecated"},
+ {1261, nullptr, "GetButtonConfigStorageLeftDeprecated"},
+ {1262, nullptr, "GetButtonConfigStorageRightDeprecated"},
+ {1263, nullptr, "SetButtonConfigStorageEmbeddedDeprecated"},
+ {1264, nullptr, "SetButtonConfigStorageFullDeprecated"},
+ {1265, nullptr, "SetButtonConfigStorageLeftDeprecated"},
+ {1266, nullptr, "SetButtonConfigStorageRightDeprecated"},
+ {1267, nullptr, "DeleteButtonConfigStorageEmbedded"},
+ {1268, nullptr, "DeleteButtonConfigStorageFull"},
+ {1269, nullptr, "DeleteButtonConfigStorageLeft"},
+ {1270, nullptr, "DeleteButtonConfigStorageRight"},
+ {1271, nullptr, "IsUsingCustomButtonConfig"},
+ {1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
+ {1273, nullptr, "SetAllCustomButtonConfigEnabled"},
+ {1274, nullptr, "SetDefaultButtonConfig"},
+ {1275, nullptr, "SetAllDefaultButtonConfig"},
+ {1276, nullptr, "SetHidButtonConfigEmbedded"},
+ {1277, nullptr, "SetHidButtonConfigFull"},
+ {1278, nullptr, "SetHidButtonConfigLeft"},
+ {1279, nullptr, "SetHidButtonConfigRight"},
+ {1280, nullptr, "GetHidButtonConfigEmbedded"},
+ {1281, nullptr, "GetHidButtonConfigFull"},
+ {1282, nullptr, "GetHidButtonConfigLeft"},
+ {1283, nullptr, "GetHidButtonConfigRight"},
+ {1284, nullptr, "GetButtonConfigStorageEmbedded"},
+ {1285, nullptr, "GetButtonConfigStorageFull"},
+ {1286, nullptr, "GetButtonConfigStorageLeft"},
+ {1287, nullptr, "GetButtonConfigStorageRight"},
+ {1288, nullptr, "SetButtonConfigStorageEmbedded"},
+ {1289, nullptr, "SetButtonConfigStorageFull"},
+ {1290, nullptr, "DeleteButtonConfigStorageRight"},
+ {1291, nullptr, "DeleteButtonConfigStorageRight"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+
+ joy_detach_event = service_context.CreateEvent("IHidSystemServer::JoyDetachEvent");
+ acquire_device_registered_event =
+ service_context.CreateEvent("IHidSystemServer::AcquireDeviceRegisteredEvent");
+ acquire_connection_trigger_timeout_event =
+ service_context.CreateEvent("IHidSystemServer::AcquireConnectionTriggerTimeoutEvent");
+ unique_pad_connection_event =
+ service_context.CreateEvent("IHidSystemServer::AcquireUniquePadConnectionEventHandle");
+}
+
+IHidSystemServer::~IHidSystemServer() {
+ service_context.CloseEvent(joy_detach_event);
+ service_context.CloseEvent(acquire_device_registered_event);
+ service_context.CloseEvent(acquire_connection_trigger_timeout_event);
+ service_context.CloseEvent(unique_pad_connection_event);
+};
+
+void IHidSystemServer::ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "called");
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .ApplyNpadSystemCommonPolicy();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::GetLastActiveNpad(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "(STUBBED) called"); // Spams a lot when controller applet is running
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(system.HIDCore().GetLastActiveController());
+}
+
+void IHidSystemServer::ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "called");
+
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .ApplyNpadSystemCommonPolicy();
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::GetNpadFullKeyGripColor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
+ npad_id_type); // Spams a lot when controller applet is running
+
+ Core::HID::NpadColor left_color{};
+ Core::HID::NpadColor right_color{};
+ // TODO: Get colors from Npad
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(left_color);
+ rb.PushRaw(right_color);
+}
+
+void IHidSystemServer::GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ LOG_INFO(Service_HID, "(STUBBED) called");
+
+ Core::HID::NpadStyleSet supported_styleset =
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetSupportedStyleSet()
+ .raw;
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(supported_styleset);
+}
+
+void IHidSystemServer::SetSupportedNpadStyleSetAll(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ LOG_INFO(Service_HID, "(STUBBED) called");
+
+ Core::HID::NpadStyleSet supported_styleset =
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetSupportedStyleSet()
+ .raw;
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(supported_styleset);
+}
+
+void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
+
+ LOG_DEBUG(Service_HID, "called, npad_id_type={}",
+ npad_id_type); // Spams a lot when controller applet is running
+
+ const Service::HID::Controller_NPad::AppletDetailedUiType detailed_ui_type =
+ GetResourceManager()
+ ->GetController<Controller_NPad>(HidController::NPad)
+ .GetAppletDetailedUiType(npad_id_type);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(detailed_ui_type);
+}
+
+void IHidSystemServer::GetNpadInterfaceType(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
+ npad_id_type); // Spams a lot when controller applet is running
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
+}
+
+void IHidSystemServer::GetNpadLeftRightInterfaceType(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
+ npad_id_type); // Spams a lot when controller applet is running
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
+ rb.PushEnum(Core::HID::NpadInterfaceType::Bluetooth);
+}
+
+void IHidSystemServer::HasBattery(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
+ npad_id_type); // Spams a lot when controller applet is running
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(false);
+}
+
+void IHidSystemServer::HasLeftRightBattery(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
+ npad_id_type); // Spams a lot when controller applet is running
+
+ struct LeftRightBattery {
+ bool left;
+ bool right;
+ };
+
+ LeftRightBattery left_right_battery{
+ .left = false,
+ .right = false,
+ };
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(left_right_battery);
+}
+
+void IHidSystemServer::GetUniquePadsFromNpad(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, npad_id_type={}",
+ npad_id_type); // Spams a lot when controller applet is running
+
+ const std::vector<Core::HID::UniquePadId> unique_pads{};
+
+ if (!unique_pads.empty()) {
+ ctx.WriteBuffer(unique_pads);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<u32>(unique_pads.size()));
+}
+
+void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) {
+ LOG_INFO(Service_AM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(acquire_device_registered_event->GetReadableEvent());
+}
+
+void IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx) {
+ LOG_INFO(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(acquire_device_registered_event->GetReadableEvent());
+}
+
+void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ struct RegisterData {
+ std::array<u8, 0x68> data;
+ };
+ static_assert(sizeof(RegisterData) == 0x68, "RegisterData is an invalid size");
+ std::vector<RegisterData> registered_devices{};
+
+ if (!registered_devices.empty()) {
+ ctx.WriteBuffer(registered_devices);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push<u64>(registered_devices.size());
+}
+
+void IHidSystemServer::AcquireUniquePadConnectionEventHandle(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.PushCopyObjects(unique_pad_connection_event->GetReadableEvent());
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::GetUniquePadIds(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push<u64>(0);
+}
+
+void IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx) {
+ LOG_INFO(Service_AM, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(joy_detach_event->GetReadableEvent());
+}
+
+void IHidSystemServer::IsUsbFullKeyControllerEnabled(HLERequestContext& ctx) {
+ const bool is_enabled = false;
+
+ LOG_WARNING(Service_HID, "(STUBBED) called, is_enabled={}", is_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(is_enabled);
+}
+
+void IHidSystemServer::IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx) {
+ const bool button_pressed = false;
+
+ LOG_DEBUG(Service_HID, "(STUBBED) called, is_enabled={}",
+ button_pressed); // Spams a lot when controller applet is open
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(button_pressed);
+}
+
+void IHidSystemServer::InitializeFirmwareUpdate(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx) {
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+
+ Core::HID::TouchScreenConfigurationForNx touchscreen_config{
+ .mode = Core::HID::TouchScreenModeForNx::Finger,
+ };
+
+ if (touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Heat2 &&
+ touchscreen_config.mode != Core::HID::TouchScreenModeForNx::Finger) {
+ touchscreen_config.mode = Core::HID::TouchScreenModeForNx::UseSystemSetting;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(touchscreen_config);
+}
+
+std::shared_ptr<ResourceManager> IHidSystemServer::GetResourceManager() {
+ resource_manager->Initialize();
+ return resource_manager;
+}
+
+} // 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..822d5e5b9
--- /dev/null
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -0,0 +1,63 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KEvent;
+}
+
+namespace Service::HID {
+class ResourceManager;
+
+class IHidSystemServer final : public ServiceFramework<IHidSystemServer> {
+public:
+ explicit IHidSystemServer(Core::System& system_, std::shared_ptr<ResourceManager> resource);
+ ~IHidSystemServer() override;
+
+private:
+ void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx);
+ void EnableAssigningSingleOnSlSrPress(HLERequestContext& ctx);
+ void DisableAssigningSingleOnSlSrPress(HLERequestContext& ctx);
+ void GetLastActiveNpad(HLERequestContext& ctx);
+ void ApplyNpadSystemCommonPolicyFull(HLERequestContext& ctx);
+ void GetNpadFullKeyGripColor(HLERequestContext& ctx);
+ void GetMaskedSupportedNpadStyleSet(HLERequestContext& ctx);
+ void SetSupportedNpadStyleSetAll(HLERequestContext& ctx);
+ void GetAppletDetailedUiType(HLERequestContext& ctx);
+ void GetNpadInterfaceType(HLERequestContext& ctx);
+ void GetNpadLeftRightInterfaceType(HLERequestContext& ctx);
+ void HasBattery(HLERequestContext& ctx);
+ void HasLeftRightBattery(HLERequestContext& ctx);
+ void GetUniquePadsFromNpad(HLERequestContext& ctx);
+ void GetIrSensorState(HLERequestContext& ctx);
+ void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
+ void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
+ void GetRegisteredDevices(HLERequestContext& ctx);
+ void AcquireUniquePadConnectionEventHandle(HLERequestContext& ctx);
+ void GetUniquePadIds(HLERequestContext& ctx);
+ void AcquireJoyDetachOnBluetoothOffEventHandle(HLERequestContext& ctx);
+ void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
+ void IsHandheldButtonPressedOnConsoleMode(HLERequestContext& ctx);
+ void InitializeFirmwareUpdate(HLERequestContext& ctx);
+ void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx);
+ void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
+
+ std::shared_ptr<ResourceManager> GetResourceManager();
+
+ Kernel::KEvent* acquire_connection_trigger_timeout_event;
+ Kernel::KEvent* acquire_device_registered_event;
+ Kernel::KEvent* joy_detach_event;
+ Kernel::KEvent* unique_pad_connection_event;
+ KernelHelpers::ServiceContext service_context;
+ std::shared_ptr<ResourceManager> resource_manager;
+};
+
+} // 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 @@
#pragma once
+#include "core/core.h"
#include "core/hid/hid_types.h"
#include "core/hid/irs_types.h"
#include "core/hle/service/hid/irsensor/processor_base.h"
#include "core/hle/service/service.h"
-namespace Core {
-class System;
-}
-
namespace Core::HID {
class EmulatedController;
} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/core_timing.h"
+#include "core/hid/hid_core.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/service/hid/resource_manager.h"
+#include "core/hle/service/ipc_helpers.h"
+
+#include "core/hle/service/hid/controllers/console_sixaxis.h"
+#include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/hle/service/hid/controllers/debug_pad.h"
+#include "core/hle/service/hid/controllers/gesture.h"
+#include "core/hle/service/hid/controllers/keyboard.h"
+#include "core/hle/service/hid/controllers/mouse.h"
+#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/controllers/palma.h"
+#include "core/hle/service/hid/controllers/stubbed.h"
+#include "core/hle/service/hid/controllers/touchscreen.h"
+#include "core/hle/service/hid/controllers/xpad.h"
+
+namespace Service::HID {
+
+// Updating period for each HID device.
+// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
+// Correct npad_update_ns is 4ms this is overclocked to lower input lag
+constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
+constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
+constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
+constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
+
+ResourceManager::ResourceManager(Core::System& system_)
+ : system{system_}, service_context{system_, "hid"} {}
+
+ResourceManager::~ResourceManager() = default;
+
+void ResourceManager::Initialize() {
+ if (is_initialized) {
+ return;
+ }
+
+ u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
+ MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory);
+ MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory);
+ MakeController<Controller_Mouse>(HidController::Mouse, shared_memory);
+ MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory);
+ MakeController<Controller_XPad>(HidController::XPad, shared_memory);
+ MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory);
+ MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory);
+ MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory);
+ MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory);
+ MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory);
+ MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory);
+ MakeController<Controller_Gesture>(HidController::Gesture, shared_memory);
+ MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory);
+ MakeController<Controller_Stubbed>(HidController::DebugMouse, shared_memory);
+ MakeControllerWithServiceContext<Controller_Palma>(HidController::Palma, shared_memory);
+
+ // Homebrew doesn't try to activate some controllers, so we activate them by default
+ GetController<Controller_NPad>(HidController::NPad).Activate();
+ GetController<Controller_Touchscreen>(HidController::Touchscreen).Activate();
+
+ GetController<Controller_Stubbed>(HidController::HomeButton).SetCommonHeaderOffset(0x4C00);
+ GetController<Controller_Stubbed>(HidController::SleepButton).SetCommonHeaderOffset(0x4E00);
+ GetController<Controller_Stubbed>(HidController::CaptureButton).SetCommonHeaderOffset(0x5000);
+ GetController<Controller_Stubbed>(HidController::InputDetector).SetCommonHeaderOffset(0x5200);
+ GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
+ GetController<Controller_Stubbed>(HidController::DebugMouse).SetCommonHeaderOffset(0x3DC00);
+
+ system.HIDCore().ReloadInputDevices();
+ is_initialized = true;
+}
+
+void ResourceManager::UpdateControllers(std::uintptr_t user_data,
+ std::chrono::nanoseconds ns_late) {
+ auto& core_timing = system.CoreTiming();
+
+ for (const auto& controller : controllers) {
+ // Keyboard has it's own update event
+ if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
+ continue;
+ }
+ // Mouse has it's own update event
+ if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
+ continue;
+ }
+ // Npad has it's own update event
+ if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
+ continue;
+ }
+ controller->OnUpdate(core_timing);
+ }
+}
+
+void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ auto& core_timing = system.CoreTiming();
+
+ controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
+}
+
+void ResourceManager::UpdateMouseKeyboard(std::uintptr_t user_data,
+ std::chrono::nanoseconds ns_late) {
+ auto& core_timing = system.CoreTiming();
+
+ controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing);
+ controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing);
+}
+
+void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
+ auto& core_timing = system.CoreTiming();
+
+ controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing);
+}
+
+IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource)
+ : ServiceFramework{system_, "IAppletResource"} {
+ static const FunctionInfo functions[] = {
+ {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
+ };
+ RegisterHandlers(functions);
+
+ resource->Initialize();
+
+ // Register update callbacks
+ npad_update_event = Core::Timing::CreateEvent(
+ "HID::UpdatePadCallback",
+ [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
+ -> std::optional<std::chrono::nanoseconds> {
+ const auto guard = LockService();
+ resource->UpdateNpad(user_data, ns_late);
+ return std::nullopt;
+ });
+ default_update_event = Core::Timing::CreateEvent(
+ "HID::UpdateDefaultCallback",
+ [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
+ -> std::optional<std::chrono::nanoseconds> {
+ const auto guard = LockService();
+ resource->UpdateControllers(user_data, ns_late);
+ return std::nullopt;
+ });
+ mouse_keyboard_update_event = Core::Timing::CreateEvent(
+ "HID::UpdateMouseKeyboardCallback",
+ [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
+ -> std::optional<std::chrono::nanoseconds> {
+ const auto guard = LockService();
+ resource->UpdateMouseKeyboard(user_data, ns_late);
+ return std::nullopt;
+ });
+ motion_update_event = Core::Timing::CreateEvent(
+ "HID::UpdateMotionCallback",
+ [this, resource](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)
+ -> std::optional<std::chrono::nanoseconds> {
+ const auto guard = LockService();
+ resource->UpdateMotion(user_data, ns_late);
+ return std::nullopt;
+ });
+
+ system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
+ system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
+ default_update_event);
+ system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
+ mouse_keyboard_update_event);
+ system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
+ motion_update_event);
+}
+
+IAppletResource::~IAppletResource() {
+ system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
+ system.CoreTiming().UnscheduleEvent(default_update_event, 0);
+ system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
+ system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
+}
+
+void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_HID, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
+}
+
+} // 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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <chrono>
+
+#include "core/core.h"
+#include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/service.h"
+
+namespace Core::Timing {
+struct EventType;
+}
+
+namespace Core::HID {
+class HIDCore;
+}
+
+namespace Service::HID {
+
+enum class HidController : std::size_t {
+ DebugPad,
+ Touchscreen,
+ Mouse,
+ Keyboard,
+ XPad,
+ HomeButton,
+ SleepButton,
+ CaptureButton,
+ InputDetector,
+ UniquePad,
+ NPad,
+ Gesture,
+ ConsoleSixAxisSensor,
+ DebugMouse,
+ Palma,
+
+ MaxControllers,
+};
+class ResourceManager {
+public:
+ explicit ResourceManager(Core::System& system_);
+ ~ResourceManager();
+
+ template <typename T>
+ T& GetController(HidController controller) {
+ return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
+ }
+
+ template <typename T>
+ const T& GetController(HidController controller) const {
+ return static_cast<T&>(*controllers[static_cast<size_t>(controller)]);
+ }
+
+ void Initialize();
+
+ void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+ void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+ void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+ void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+
+private:
+ template <typename T>
+ void MakeController(HidController controller, u8* shared_memory) {
+ if constexpr (std::is_constructible_v<T, Core::System&, u8*>) {
+ controllers[static_cast<std::size_t>(controller)] =
+ std::make_unique<T>(system, shared_memory);
+ } else {
+ controllers[static_cast<std::size_t>(controller)] =
+ std::make_unique<T>(system.HIDCore(), shared_memory);
+ }
+ }
+
+ template <typename T>
+ void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) {
+ controllers[static_cast<std::size_t>(controller)] =
+ std::make_unique<T>(system.HIDCore(), shared_memory, service_context);
+ }
+
+ bool is_initialized{false};
+ std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
+ controllers{};
+
+ Core::System& system;
+ KernelHelpers::ServiceContext service_context;
+};
+
+class IAppletResource final : public ServiceFramework<IAppletResource> {
+public:
+ explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource);
+ ~IAppletResource() override;
+
+private:
+ void GetSharedMemoryHandle(HLERequestContext& ctx);
+
+ std::shared_ptr<Core::Timing::EventType> npad_update_event;
+ std::shared_ptr<Core::Timing::EventType> default_update_event;
+ std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
+ std::shared_ptr<Core::Timing::EventType> motion_update_event;
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 7927f8264..961f89a14 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -115,12 +115,20 @@ public:
{400, nullptr, "InitializeSystem"},
{401, nullptr, "FinalizeSystem"},
{402, nullptr, "SetOperationMode"},
- {403, nullptr, "InitializeSystem2"},
+ {403, &ISystemLocalCommunicationService::InitializeSystem2, "InitializeSystem2"},
};
// clang-format on
RegisterHandlers(functions);
}
+
+private:
+ void InitializeSystem2(HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
};
class IUserLocalCommunicationService final
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 @@
namespace Service::android {
-struct GraphicBuffer;
+class GraphicBuffer;
class BufferItem final {
public:
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 @@
// https://cs.android.com/android/platform/superproject/+/android-5.1.1_r38:frameworks/native/libs/gui/BufferQueueConsumer.cpp
#include "common/logging/log.h"
-#include "core/hle/service/nvdrv/core/nvmap.h"
#include "core/hle/service/nvnflinger/buffer_item.h"
#include "core/hle/service/nvnflinger/buffer_queue_consumer.h"
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
@@ -14,9 +13,8 @@
namespace Service::android {
-BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_,
- Service::Nvidia::NvCore::NvMap& nvmap_)
- : core{std::move(core_)}, slots{core->slots}, nvmap(nvmap_) {}
+BufferQueueConsumer::BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_)
+ : core{std::move(core_)}, slots{core->slots} {}
BufferQueueConsumer::~BufferQueueConsumer() = default;
@@ -136,8 +134,6 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc
slots[slot].buffer_state = BufferState::Free;
- nvmap.FreeHandle(slots[slot].graphic_buffer->BufferId(), true);
-
listener = core->connected_producer_listener;
LOG_DEBUG(Service_Nvnflinger, "releasing slot {}", slot);
@@ -175,6 +171,25 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_
return Status::NoError;
}
+Status BufferQueueConsumer::Disconnect() {
+ LOG_DEBUG(Service_Nvnflinger, "called");
+
+ std::scoped_lock lock{core->mutex};
+
+ if (core->consumer_listener == nullptr) {
+ LOG_ERROR(Service_Nvnflinger, "no consumer is connected");
+ return Status::BadValue;
+ }
+
+ core->is_abandoned = true;
+ core->consumer_listener = nullptr;
+ core->queue.clear();
+ core->FreeAllBuffersLocked();
+ core->SignalDequeueCondition();
+
+ return Status::NoError;
+}
+
Status BufferQueueConsumer::GetReleasedBuffers(u64* out_slot_mask) {
if (out_slot_mask == nullptr) {
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 @@
#include "core/hle/service/nvnflinger/buffer_queue_defs.h"
#include "core/hle/service/nvnflinger/status.h"
-namespace Service::Nvidia::NvCore {
-class NvMap;
-} // namespace Service::Nvidia::NvCore
-
namespace Service::android {
class BufferItem;
@@ -25,19 +21,18 @@ class IConsumerListener;
class BufferQueueConsumer final {
public:
- explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_,
- Service::Nvidia::NvCore::NvMap& nvmap_);
+ explicit BufferQueueConsumer(std::shared_ptr<BufferQueueCore> core_);
~BufferQueueConsumer();
Status AcquireBuffer(BufferItem* out_buffer, std::chrono::nanoseconds expected_present);
Status ReleaseBuffer(s32 slot, u64 frame_number, const Fence& release_fence);
Status Connect(std::shared_ptr<IConsumerListener> consumer_listener, bool controlled_by_app);
+ Status Disconnect();
Status GetReleasedBuffers(u64* out_slot_mask);
private:
std::shared_ptr<BufferQueueCore> core;
BufferQueueDefs::SlotsType& slots;
- Service::Nvidia::NvCore::NvMap& nvmap;
};
} // 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;
BufferQueueCore::~BufferQueueCore() = default;
-void BufferQueueCore::NotifyShutdown() {
- std::scoped_lock lock{mutex};
-
- is_shutting_down = true;
-
- SignalDequeueCondition();
-}
-
void BufferQueueCore::SignalDequeueCondition() {
dequeue_possible.store(true);
dequeue_condition.notify_all();
}
bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {
- if (is_shutting_down) {
- return false;
- }
-
dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); });
dequeue_possible.store(false);
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:
BufferQueueCore();
~BufferQueueCore();
- void NotifyShutdown();
-
private:
void SignalDequeueCondition();
bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
@@ -74,7 +72,6 @@ private:
u32 transform_hint{};
bool is_allocating{};
mutable std::condition_variable_any is_allocating_condition;
- bool is_shutting_down{};
};
} // 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 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/nvdrv/core/nvmap.h"
#include "core/hle/service/nvnflinger/buffer_queue_core.h"
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
#include "core/hle/service/nvnflinger/consumer_listener.h"
@@ -533,8 +532,6 @@ Status BufferQueueProducer::QueueBuffer(s32 slot, const QueueBufferInput& input,
item.is_droppable = core->dequeue_buffer_cannot_block || async;
item.swap_interval = swap_interval;
- nvmap.DuplicateHandle(item.graphic_buffer->BufferId(), true);
-
sticky_transform = sticky_transform_;
if (core->queue.empty()) {
@@ -744,19 +741,13 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
return Status::NoError;
}
- // HACK: We are not Android. Remove handle for items in queue, and clear queue.
- // Allows synchronous destruction of nvmap handles.
- for (auto& item : core->queue) {
- nvmap.FreeHandle(item.graphic_buffer->BufferId(), true);
- }
- core->queue.clear();
-
switch (api) {
case NativeWindowApi::Egl:
case NativeWindowApi::Cpu:
case NativeWindowApi::Media:
case NativeWindowApi::Camera:
if (core->connected_api == api) {
+ core->queue.clear();
core->FreeAllBuffersLocked();
core->connected_producer_listener = nullptr;
core->connected_api = NativeWindowApi::NoConnectedApi;
@@ -785,7 +776,7 @@ Status BufferQueueProducer::Disconnect(NativeWindowApi api) {
}
Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
- const std::shared_ptr<GraphicBuffer>& buffer) {
+ const std::shared_ptr<NvGraphicBuffer>& buffer) {
LOG_DEBUG(Service_Nvnflinger, "slot {}", slot);
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
@@ -796,7 +787,7 @@ Status BufferQueueProducer::SetPreallocatedBuffer(s32 slot,
slots[slot] = {};
slots[slot].fence = Fence::NoFence();
- slots[slot].graphic_buffer = buffer;
+ slots[slot].graphic_buffer = std::make_shared<GraphicBuffer>(nvmap, buffer);
slots[slot].frame_number = 0;
// 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
}
case TransactionId::SetPreallocatedBuffer: {
const auto slot = parcel_in.Read<s32>();
- const auto buffer = parcel_in.ReadObject<GraphicBuffer>();
+ const auto buffer = parcel_in.ReadObject<NvGraphicBuffer>();
status = SetPreallocatedBuffer(slot, buffer);
break;
@@ -867,7 +858,7 @@ void BufferQueueProducer::Transact(HLERequestContext& ctx, TransactionId code, u
status = RequestBuffer(slot, &buf);
- parcel_out.WriteFlattenedObject(buf);
+ parcel_out.WriteFlattenedObject<NvGraphicBuffer>(buf.get());
break;
}
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 {
class BufferQueueCore;
class IProducerListener;
+struct NvGraphicBuffer;
class BufferQueueProducer final : public IBinder {
public:
@@ -65,7 +66,7 @@ public:
bool producer_controlled_by_app, QueueBufferOutput* output);
Status Disconnect(NativeWindowApi api);
- Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<GraphicBuffer>& buffer);
+ Status SetPreallocatedBuffer(s32 slot, const std::shared_ptr<NvGraphicBuffer>& buffer);
private:
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 @@
namespace Service::android {
-struct GraphicBuffer;
+class GraphicBuffer;
enum class BufferState : u32 {
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) {
consumer->Connect(shared_from_this(), controlled_by_app);
}
+void ConsumerBase::Abandon() {
+ LOG_DEBUG(Service_Nvnflinger, "called");
+
+ std::scoped_lock lock{mutex};
+
+ if (!is_abandoned) {
+ this->AbandonLocked();
+ is_abandoned = true;
+ }
+}
+
+void ConsumerBase::AbandonLocked() {
+ for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
+ this->FreeBufferLocked(i);
+ }
+ // disconnect from the BufferQueue
+ consumer->Disconnect();
+ consumer = nullptr;
+}
+
void ConsumerBase::FreeBufferLocked(s32 slot_index) {
LOG_DEBUG(Service_Nvnflinger, "slot_index={}", slot_index);
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;
class ConsumerBase : public IConsumerListener, public std::enable_shared_from_this<ConsumerBase> {
public:
void Connect(bool controlled_by_app);
+ void Abandon();
protected:
explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_);
@@ -34,6 +35,7 @@ protected:
void OnBuffersReleased() override;
void OnSidebandStreamChanged() override;
+ void AbandonLocked();
void FreeBufferLocked(s32 slot_index);
Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when);
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 = [] {
}();
void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 handle) {
- auto buffer = std::make_shared<android::GraphicBuffer>();
+ auto buffer = std::make_shared<android::NvGraphicBuffer>();
buffer->width = SharedBufferWidth;
buffer->height = SharedBufferHeight;
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) {
vsync_signal.Wait();
const auto lock_guard = Lock();
- Compose();
+
+ if (!is_abandoned) {
+ Compose();
+ }
}
}
@@ -98,7 +101,6 @@ Nvnflinger::~Nvnflinger() {
}
ShutdownLayers();
- vsync_thread = {};
if (nvdrv) {
nvdrv->Close(disp_fd);
@@ -106,12 +108,20 @@ Nvnflinger::~Nvnflinger() {
}
void Nvnflinger::ShutdownLayers() {
- const auto lock_guard = Lock();
- for (auto& display : displays) {
- for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
- display.GetLayer(layer).Core().NotifyShutdown();
+ // Abandon consumers.
+ {
+ const auto lock_guard = Lock();
+ for (auto& display : displays) {
+ for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
+ display.GetLayer(layer).GetConsumer().Abandon();
+ }
}
+
+ is_abandoned = true;
}
+
+ // Join the vsync thread, if it exists.
+ vsync_thread = {};
}
void 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:
s32 swap_interval = 1;
+ bool is_abandoned = false;
+
/// Event that handles screen composition.
std::shared_ptr<Core::Timing::EventType> multi_composition_event;
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 {
Busy = -16,
NoInit = -19,
BadValue = -22,
- InvalidOperation = -37,
+ InvalidOperation = -38,
BufferNeedsReallocation = 1,
ReleaseAllBuffers = 2,
};
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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/hle/service/nvdrv/core/nvmap.h"
+#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
+
+namespace Service::android {
+
+static NvGraphicBuffer GetBuffer(std::shared_ptr<NvGraphicBuffer>& buffer) {
+ if (buffer) {
+ return *buffer;
+ } else {
+ return {};
+ }
+}
+
+GraphicBuffer::GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
+ : NvGraphicBuffer(width_, height_, format_, usage_), m_nvmap(nullptr) {}
+
+GraphicBuffer::GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
+ std::shared_ptr<NvGraphicBuffer> buffer)
+ : NvGraphicBuffer(GetBuffer(buffer)), m_nvmap(std::addressof(nvmap)) {
+ if (this->BufferId() > 0) {
+ m_nvmap->DuplicateHandle(this->BufferId(), true);
+ }
+}
+
+GraphicBuffer::~GraphicBuffer() {
+ if (m_nvmap != nullptr && this->BufferId() > 0) {
+ m_nvmap->FreeHandle(this->BufferId(), true);
+ }
+}
+
+} // 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 @@
#pragma once
+#include <memory>
+
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/service/nvnflinger/pixel_format.h"
+namespace Service::Nvidia::NvCore {
+class NvMap;
+} // namespace Service::Nvidia::NvCore
+
namespace Service::android {
-struct GraphicBuffer final {
- constexpr GraphicBuffer() = default;
+struct NvGraphicBuffer {
+ constexpr NvGraphicBuffer() = default;
- constexpr GraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
+ constexpr NvGraphicBuffer(u32 width_, u32 height_, PixelFormat format_, u32 usage_)
: width{static_cast<s32>(width_)}, height{static_cast<s32>(height_)}, format{format_},
usage{static_cast<s32>(usage_)} {}
@@ -93,6 +99,17 @@ struct GraphicBuffer final {
u32 offset{};
INSERT_PADDING_WORDS(60);
};
-static_assert(sizeof(GraphicBuffer) == 0x16C, "GraphicBuffer has wrong size");
+static_assert(sizeof(NvGraphicBuffer) == 0x16C, "NvGraphicBuffer has wrong size");
+
+class GraphicBuffer final : public NvGraphicBuffer {
+public:
+ explicit GraphicBuffer(u32 width, u32 height, PixelFormat format, u32 usage);
+ explicit GraphicBuffer(Service::Nvidia::NvCore::NvMap& nvmap,
+ std::shared_ptr<NvGraphicBuffer> buffer);
+ ~GraphicBuffer();
+
+private:
+ Service::Nvidia::NvCore::NvMap* m_nvmap{};
+};
} // namespace Service::android
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index ec3af80af..19c667b42 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -431,8 +431,7 @@ void SET_SYS::GetAutoUpdateEnableFlag(HLERequestContext& ctx) {
void SET_SYS::GetBatteryPercentageFlag(HLERequestContext& ctx) {
u8 battery_percentage_flag{1};
- LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}",
- battery_percentage_flag);
+ LOG_DEBUG(Service_SET, "(STUBBED) called, battery_percentage_flag={}", battery_percentage_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@@ -492,6 +491,29 @@ void SET_SYS::GetChineseTraditionalInputMethod(HLERequestContext& ctx) {
rb.PushEnum(ChineseTraditionalInputMethod::Unknown0);
}
+void SET_SYS::GetHomeMenuScheme(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_SET, "(STUBBED) called");
+
+ const HomeMenuScheme default_color = {
+ .main = 0xFF323232,
+ .back = 0xFF323232,
+ .sub = 0xFFFFFFFF,
+ .bezel = 0xFFFFFFFF,
+ .extra = 0xFF000000,
+ };
+
+ IPC::ResponseBuilder rb{ctx, 7};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(default_color);
+}
+
+void SET_SYS::GetHomeMenuSchemeModel(HLERequestContext& ctx) {
+ LOG_WARNING(Service_SET, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(0);
+}
void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
@@ -674,7 +696,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{171, nullptr, "SetChineseTraditionalInputMethod"},
{172, nullptr, "GetPtmCycleCountReliability"},
{173, nullptr, "SetPtmCycleCountReliability"},
- {174, nullptr, "GetHomeMenuScheme"},
+ {174, &SET_SYS::GetHomeMenuScheme, "GetHomeMenuScheme"},
{175, nullptr, "GetThemeSettings"},
{176, nullptr, "SetThemeSettings"},
{177, nullptr, "GetThemeKey"},
@@ -685,7 +707,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} {
{182, nullptr, "SetT"},
{183, nullptr, "GetPlatformRegion"},
{184, nullptr, "SetPlatformRegion"},
- {185, nullptr, "GetHomeMenuSchemeModel"},
+ {185, &SET_SYS::GetHomeMenuSchemeModel, "GetHomeMenuSchemeModel"},
{186, nullptr, "GetMemoryUsageRateFlag"},
{187, nullptr, "GetTouchScreenMode"},
{188, nullptr, "SetTouchScreenMode"},
diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h
index c7dba2a9e..93023c6dd 100644
--- a/src/core/hle/service/set/set_sys.h
+++ b/src/core/hle/service/set/set_sys.h
@@ -269,6 +269,16 @@ private:
};
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
+ /// This is nn::settings::system::HomeMenuScheme
+ struct HomeMenuScheme {
+ u32 main;
+ u32 back;
+ u32 sub;
+ u32 bezel;
+ u32 extra;
+ };
+ static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size");
+
void SetLanguageCode(HLERequestContext& ctx);
void GetFirmwareVersion(HLERequestContext& ctx);
void GetFirmwareVersion2(HLERequestContext& ctx);
@@ -305,6 +315,8 @@ private:
void GetKeyboardLayout(HLERequestContext& ctx);
void GetChineseTraditionalInputMethod(HLERequestContext& ctx);
void GetFieldTestingFlag(HLERequestContext& ctx);
+ void GetHomeMenuScheme(HLERequestContext& ctx);
+ void GetHomeMenuSchemeModel(HLERequestContext& ctx);
AccountSettings account_settings{
.flags = {},
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
return {
buffer_queue_core,
std::make_unique<android::BufferQueueProducer>(service_context, buffer_queue_core, nvmap),
- std::make_unique<android::BufferQueueConsumer>(buffer_queue_core, nvmap)};
+ std::make_unique<android::BufferQueueConsumer>(buffer_queue_core)};
}
Display::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 @@
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
+// SPDX-FileCopyrightText: 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <cstring>
+#include <mutex>
#include <span>
#include "common/assert.h"
@@ -10,6 +12,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/page_table.h"
+#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/swap.h"
#include "core/core.h"
@@ -318,7 +321,7 @@ struct Memory::Impl {
[&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
u8* const host_ptr) {
if constexpr (!UNSAFE) {
- system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount);
+ HandleRasterizerWrite(GetInteger(current_vaddr), copy_amount);
}
std::memcpy(host_ptr, src_buffer, copy_amount);
},
@@ -351,7 +354,7 @@ struct Memory::Impl {
},
[&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount,
u8* const host_ptr) {
- system.GPU().InvalidateRegion(GetInteger(current_vaddr), copy_amount);
+ HandleRasterizerWrite(GetInteger(current_vaddr), copy_amount);
std::memset(host_ptr, 0, copy_amount);
},
[](const std::size_t copy_amount) {});
@@ -420,7 +423,7 @@ struct Memory::Impl {
const std::size_t block_size) {
// dc cvac: Store to point of coherency
// CPU flush -> GPU invalidate
- system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
+ HandleRasterizerWrite(GetInteger(current_vaddr), block_size);
};
return PerformCacheOperation(dest_addr, size, on_rasterizer);
}
@@ -430,7 +433,7 @@ struct Memory::Impl {
const std::size_t block_size) {
// dc civac: Store to point of coherency, and invalidate from cache
// CPU flush -> GPU invalidate
- system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size);
+ HandleRasterizerWrite(GetInteger(current_vaddr), block_size);
};
return PerformCacheOperation(dest_addr, size, on_rasterizer);
}
@@ -767,7 +770,18 @@ struct Memory::Impl {
}
void HandleRasterizerWrite(VAddr address, size_t size) {
- const size_t core = system.GetCurrentHostThreadID();
+ constexpr size_t sys_core = Core::Hardware::NUM_CPU_CORES - 1;
+ const size_t core = std::min(system.GetCurrentHostThreadID(),
+ sys_core); // any other calls threads go to syscore.
+ // Guard on sys_core;
+ if (core == sys_core) [[unlikely]] {
+ sys_core_guard.lock();
+ }
+ SCOPE_EXIT({
+ if (core == sys_core) [[unlikely]] {
+ sys_core_guard.unlock();
+ }
+ });
auto& current_area = rasterizer_write_areas[core];
VAddr subaddress = address >> YUZU_PAGEBITS;
bool do_collection = current_area.last_address == subaddress;
@@ -799,6 +813,7 @@ struct Memory::Impl {
rasterizer_read_areas{};
std::array<GPUDirtyState, Core::Hardware::NUM_CPU_CORES> rasterizer_write_areas{};
std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
+ std::mutex sys_core_guard;
};
Memory::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 @@
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/hid/controllers/npad.h"
-#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/hid/hid_server.h"
+#include "core/hle/service/hid/resource_manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/memory.h"
#include "core/memory/cheat_engine.h"
@@ -54,13 +55,13 @@ void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size)
}
u64 StandardVmCallbacks::HidKeysDown() {
- const auto hid = system.ServiceManager().GetService<Service::HID::Hid>("hid");
+ const auto hid = system.ServiceManager().GetService<Service::HID::IHidServer>("hid");
if (hid == nullptr) {
LOG_WARNING(CheatEngine, "Attempted to read input state, but hid is not initialized!");
return 0;
}
- const auto applet_resource = hid->GetAppletResource();
+ const auto applet_resource = hid->GetResourceManager();
if (applet_resource == nullptr) {
LOG_WARNING(CheatEngine,
"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
// This list is missing ZL/ZR since those are not considered buttons.
// We will add those afterwards
// This list also excludes any button that can't be really mapped
- static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 12>
+ static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 14>
switch_to_gcadapter_button = {
std::pair{Settings::NativeButton::A, PadButton::ButtonA},
{Settings::NativeButton::B, PadButton::ButtonB},
@@ -426,8 +426,10 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p
{Settings::NativeButton::DUp, PadButton::ButtonUp},
{Settings::NativeButton::DRight, PadButton::ButtonRight},
{Settings::NativeButton::DDown, PadButton::ButtonDown},
- {Settings::NativeButton::SL, PadButton::TriggerL},
- {Settings::NativeButton::SR, PadButton::TriggerR},
+ {Settings::NativeButton::SLLeft, PadButton::TriggerL},
+ {Settings::NativeButton::SRLeft, PadButton::TriggerR},
+ {Settings::NativeButton::SLRight, PadButton::TriggerL},
+ {Settings::NativeButton::SRRight, PadButton::TriggerR},
{Settings::NativeButton::R, PadButton::TriggerZ},
};
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
Common::ParamPackage sr_button_params = button_params;
sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSL));
sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::LeftSR));
- mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params));
- mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params));
+ mapping.insert_or_assign(Settings::NativeButton::SLLeft, std::move(sl_button_params));
+ mapping.insert_or_assign(Settings::NativeButton::SRLeft, std::move(sr_button_params));
}
// Map SL and SR buttons for right joycons
@@ -693,8 +693,8 @@ ButtonMapping Joycons::GetButtonMappingForDevice(const Common::ParamPackage& par
Common::ParamPackage sr_button_params = button_params;
sl_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSL));
sr_button_params.Set("button", static_cast<int>(Joycon::PadButton::RightSR));
- mapping.insert_or_assign(Settings::NativeButton::SL, std::move(sl_button_params));
- mapping.insert_or_assign(Settings::NativeButton::SR, std::move(sr_button_params));
+ mapping.insert_or_assign(Settings::NativeButton::SLRight, std::move(sl_button_params));
+ mapping.insert_or_assign(Settings::NativeButton::SRRight, std::move(sr_button_params));
}
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
ButtonBindings SDLDriver::GetDefaultButtonBinding(
const std::shared_ptr<SDLJoystick>& joystick) const {
// Default SL/SR mapping for other controllers
- auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
- auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
+ auto sll_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
+ auto srl_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
+ auto slr_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
+ auto srr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
if (joystick->IsJoyconLeft()) {
- sl_button = SDL_CONTROLLER_BUTTON_PADDLE2;
- sr_button = SDL_CONTROLLER_BUTTON_PADDLE4;
+ sll_button = SDL_CONTROLLER_BUTTON_PADDLE2;
+ srl_button = SDL_CONTROLLER_BUTTON_PADDLE4;
}
if (joystick->IsJoyconRight()) {
- sl_button = SDL_CONTROLLER_BUTTON_PADDLE3;
- sr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
+ slr_button = SDL_CONTROLLER_BUTTON_PADDLE3;
+ srr_button = SDL_CONTROLLER_BUTTON_PADDLE1;
}
return {
@@ -855,8 +857,10 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding(
{Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
{Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
{Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
- {Settings::NativeButton::SL, sl_button},
- {Settings::NativeButton::SR, sr_button},
+ {Settings::NativeButton::SLLeft, sll_button},
+ {Settings::NativeButton::SRLeft, srl_button},
+ {Settings::NativeButton::SLRight, slr_button},
+ {Settings::NativeButton::SRRight, srr_button},
{Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
{Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1},
};
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 {
class SDLJoystick;
using ButtonBindings =
- std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 18>;
+ std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 20>;
using ZButtonBindings =
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
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 {
ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) {
// This list excludes any button that can't be really mapped
- static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 20>
+ static constexpr std::array<std::pair<Settings::NativeButton::Values, PadButton>, 22>
switch_to_dsu_button = {
std::pair{Settings::NativeButton::A, PadButton::Circle},
{Settings::NativeButton::B, PadButton::Cross},
@@ -412,8 +412,10 @@ ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& p
{Settings::NativeButton::R, PadButton::R1},
{Settings::NativeButton::ZL, PadButton::L2},
{Settings::NativeButton::ZR, PadButton::R2},
- {Settings::NativeButton::SL, PadButton::L2},
- {Settings::NativeButton::SR, PadButton::R2},
+ {Settings::NativeButton::SLLeft, PadButton::L2},
+ {Settings::NativeButton::SRLeft, PadButton::R2},
+ {Settings::NativeButton::SLRight, PadButton::L2},
+ {Settings::NativeButton::SRRight, PadButton::R2},
{Settings::NativeButton::LStick, PadButton::L3},
{Settings::NativeButton::RStick, PadButton::R3},
{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
ir_opt/rescaling_pass.cpp
ir_opt/ssa_rewrite_pass.cpp
ir_opt/texture_pass.cpp
+ ir_opt/vendor_workaround_pass.cpp
ir_opt/verification_pass.cpp
object_pool.h
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,
const IR::Value& offset, const IR::Value& lod_clamp) {
const auto info{inst.Flags<IR::TextureInstInfo>()};
ScopedRegister dpdx, dpdy, coords;
- const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp};
+ const bool multi_component{info.num_derivatives > 1 || info.has_lod_clamp};
if (multi_component) {
// Allocate this early to avoid aliasing other registers
dpdx = ScopedRegister{ctx.reg_alloc};
dpdy = ScopedRegister{ctx.reg_alloc};
- if (info.num_derivates >= 3) {
+ if (info.num_derivatives >= 3) {
coords = ScopedRegister{ctx.reg_alloc};
}
}
@@ -584,7 +584,7 @@ void EmitImageGradient(EmitContext& ctx, IR::Inst& inst, const IR::Value& index,
dpdx.reg, derivatives_vec, dpdx.reg, derivatives_vec, dpdy.reg, derivatives_vec,
dpdy.reg, derivatives_vec);
Register final_coord;
- if (info.num_derivates >= 3) {
+ if (info.num_derivatives >= 3) {
ctx.Add("MOV.F {}.z,{}.x;"
"MOV.F {}.z,{}.y;",
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,
if (sparse_inst) {
throw NotImplementedException("EmitImageGradient Sparse");
}
- if (!offset.IsEmpty() && info.num_derivates <= 2) {
+ if (!offset.IsEmpty() && info.num_derivatives <= 2) {
throw NotImplementedException("EmitImageGradient offset");
}
const auto texture{Texture(ctx, info, index)};
const auto texel{ctx.var_alloc.Define(inst, GlslVarType::F32x4)};
- const bool multi_component{info.num_derivates > 1 || info.has_lod_clamp};
+ const bool multi_component{info.num_derivatives > 1 || info.has_lod_clamp};
const auto derivatives_vec{ctx.var_alloc.Consume(derivatives)};
if (multi_component) {
- if (info.num_derivates >= 3) {
+ if (info.num_derivatives >= 3) {
const auto offset_vec{ctx.var_alloc.Consume(offset)};
ctx.Add("{}=textureGrad({},{},vec3({}.xz, {}.x),vec3({}.yw, {}.y));", texel, texture,
coords, derivatives_vec, offset_vec, derivatives_vec, offset_vec);
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
index 34592a01f..0031fa5fb 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp
@@ -407,7 +407,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
}
ctx.AddCapability(spv::Capability::DemoteToHelperInvocation);
}
- if (info.stores[IR::Attribute::ViewportIndex]) {
+ if (info.stores[IR::Attribute::ViewportIndex] && profile.support_multi_viewport) {
ctx.AddCapability(spv::Capability::MultiViewport);
}
if (info.stores[IR::Attribute::ViewportMask] && profile.support_viewport_mask) {
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 1d77426e0..e5a78a914 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -84,6 +84,10 @@ std::optional<OutAttr> OutputAttrPointer(EmitContext& ctx, IR::Attribute attr) {
}
return std::nullopt;
case IR::Attribute::ViewportIndex:
+ if (!ctx.profile.support_multi_viewport) {
+ LOG_WARNING(Shader, "Ignoring viewport index store on non-supporting driver");
+ return std::nullopt;
+ }
if (ctx.profile.support_viewport_index_layer_non_geometry ||
ctx.stage == Shader::Stage::Geometry) {
return OutAttr{ctx.viewport_index, ctx.U32[1]};
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:
}
}
- explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates, u32 num_derivates,
- Id offset, Id lod_clamp) {
- if (!Sirit::ValidId(derivates)) {
- throw LogicError("Derivates must be present");
+ explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives,
+ u32 num_derivatives, Id offset, Id lod_clamp) {
+ if (!Sirit::ValidId(derivatives)) {
+ throw LogicError("Derivatives must be present");
}
boost::container::static_vector<Id, 3> deriv_x_accum;
boost::container::static_vector<Id, 3> deriv_y_accum;
- for (u32 i = 0; i < num_derivates; ++i) {
- deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2));
- deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivates, i * 2 + 1));
+ for (u32 i = 0; i < num_derivatives; ++i) {
+ deriv_x_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2));
+ deriv_y_accum.push_back(ctx.OpCompositeExtract(ctx.F32[1], derivatives, i * 2 + 1));
}
- const Id derivates_X{ctx.OpCompositeConstruct(
- ctx.F32[num_derivates], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
- const Id derivates_Y{ctx.OpCompositeConstruct(
- ctx.F32[num_derivates], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
- Add(spv::ImageOperandsMask::Grad, derivates_X, derivates_Y);
+ const Id derivatives_X{ctx.OpCompositeConstruct(
+ ctx.F32[num_derivatives], std::span{deriv_x_accum.data(), deriv_x_accum.size()})};
+ const Id derivatives_Y{ctx.OpCompositeConstruct(
+ ctx.F32[num_derivatives], std::span{deriv_y_accum.data(), deriv_y_accum.size()})};
+ Add(spv::ImageOperandsMask::Grad, derivatives_X, derivatives_Y);
if (Sirit::ValidId(offset)) {
Add(spv::ImageOperandsMask::Offset, offset);
}
@@ -91,26 +91,26 @@ public:
}
}
- explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivates_1, Id derivates_2,
+ explicit ImageOperands(EmitContext& ctx, bool has_lod_clamp, Id derivatives_1, Id derivatives_2,
Id offset, Id lod_clamp) {
- if (!Sirit::ValidId(derivates_1) || !Sirit::ValidId(derivates_2)) {
- throw LogicError("Derivates must be present");
+ if (!Sirit::ValidId(derivatives_1) || !Sirit::ValidId(derivatives_2)) {
+ throw LogicError("Derivatives must be present");
}
boost::container::static_vector<Id, 3> deriv_1_accum{
- ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 0),
- ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 2),
- ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 0),
+ ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 0),
+ ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 2),
+ ctx.OpCompositeExtract(ctx.F32[1], derivatives_2, 0),
};
boost::container::static_vector<Id, 3> deriv_2_accum{
- ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 1),
- ctx.OpCompositeExtract(ctx.F32[1], derivates_1, 3),
- ctx.OpCompositeExtract(ctx.F32[1], derivates_2, 1),
+ ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 1),
+ ctx.OpCompositeExtract(ctx.F32[1], derivatives_1, 3),
+ ctx.OpCompositeExtract(ctx.F32[1], derivatives_2, 1),
};
- const Id derivates_id1{ctx.OpCompositeConstruct(
+ const Id derivatives_id1{ctx.OpCompositeConstruct(
ctx.F32[3], std::span{deriv_1_accum.data(), deriv_1_accum.size()})};
- const Id derivates_id2{ctx.OpCompositeConstruct(
+ const Id derivatives_id2{ctx.OpCompositeConstruct(
ctx.F32[3], std::span{deriv_2_accum.data(), deriv_2_accum.size()})};
- Add(spv::ImageOperandsMask::Grad, derivates_id1, derivates_id2);
+ Add(spv::ImageOperandsMask::Grad, derivatives_id1, derivatives_id2);
if (Sirit::ValidId(offset)) {
Add(spv::ImageOperandsMask::Offset, offset);
}
@@ -548,12 +548,12 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
}
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
- Id derivates, Id offset, Id lod_clamp) {
+ Id derivatives, Id offset, Id lod_clamp) {
const auto info{inst->Flags<IR::TextureInstInfo>()};
const auto operands =
- info.num_derivates == 3
- ? ImageOperands(ctx, info.has_lod_clamp != 0, derivates, offset, {}, lod_clamp)
- : ImageOperands(ctx, info.has_lod_clamp != 0, derivates, info.num_derivates, offset,
+ info.num_derivatives == 3
+ ? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, offset, {}, lod_clamp)
+ : ImageOperands(ctx, info.has_lod_clamp != 0, derivatives, info.num_derivatives, offset,
lod_clamp);
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
&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
const IR::Value& skip_mips);
Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
- Id derivates, Id offset, Id lod_clamp);
+ Id derivatives, Id offset, Id lod_clamp);
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords);
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color);
Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index);
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
return Inst(op, Flags{info}, handle, coords);
}
-Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivates,
+Value IREmitter::ImageGradient(const Value& handle, const Value& coords, const Value& derivatives,
const Value& offset, const F32& lod_clamp, TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageGradient
: Opcode::BindlessImageGradient};
- return Inst(op, Flags{info}, handle, coords, derivates, offset, lod_clamp);
+ return Inst(op, Flags{info}, handle, coords, derivatives, offset, lod_clamp);
}
Value 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:
[[nodiscard]] Value ImageFetch(const Value& handle, const Value& coords, const Value& offset,
const U32& lod, const U32& multisampling, TextureInstInfo info);
[[nodiscard]] Value ImageGradient(const Value& handle, const Value& coords,
- const Value& derivates, const Value& offset,
+ const Value& derivatives, const Value& offset,
const F32& lod_clamp, TextureInstInfo info);
[[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info);
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 {
BitField<21, 1, u32> has_lod_clamp;
BitField<22, 1, u32> relaxed_precision;
BitField<23, 2, u32> gather_component;
- BitField<25, 2, u32> num_derivates;
+ BitField<25, 2, u32> num_derivatives;
BitField<27, 3, ImageFormat> image_format;
BitField<30, 1, u32> ndv_is_active;
};
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) {
BitField<51, 3, IR::Pred> sparse_pred;
BitField<0, 8, IR::Reg> dest_reg;
BitField<8, 8, IR::Reg> coord_reg;
- BitField<20, 8, IR::Reg> derivate_reg;
+ BitField<20, 8, IR::Reg> derivative_reg;
BitField<28, 3, TextureType> type;
BitField<31, 4, u64> mask;
BitField<36, 13, u64> cbuf_offset;
@@ -71,7 +71,7 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
}
IR::Value coords;
- u32 num_derivates{};
+ u32 num_derivatives{};
IR::Reg base_reg{txd.coord_reg};
IR::Reg last_reg;
IR::Value handle;
@@ -90,42 +90,42 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
switch (txd.type) {
case TextureType::_1D: {
coords = v.F(base_reg);
- num_derivates = 1;
+ num_derivatives = 1;
last_reg = base_reg + 1;
break;
}
case TextureType::ARRAY_1D: {
last_reg = base_reg + 1;
coords = v.ir.CompositeConstruct(v.F(base_reg), read_array());
- num_derivates = 1;
+ num_derivatives = 1;
break;
}
case TextureType::_2D: {
last_reg = base_reg + 2;
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1));
- num_derivates = 2;
+ num_derivatives = 2;
break;
}
case TextureType::ARRAY_2D: {
last_reg = base_reg + 2;
coords = v.ir.CompositeConstruct(v.F(base_reg), v.F(base_reg + 1), read_array());
- num_derivates = 2;
+ num_derivatives = 2;
break;
}
default:
throw NotImplementedException("Invalid texture type");
}
- const IR::Reg derivate_reg{txd.derivate_reg};
- IR::Value derivates;
- switch (num_derivates) {
+ const IR::Reg derivative_reg{txd.derivative_reg};
+ IR::Value derivatives;
+ switch (num_derivatives) {
case 1: {
- derivates = v.ir.CompositeConstruct(v.F(derivate_reg), v.F(derivate_reg + 1));
+ derivatives = v.ir.CompositeConstruct(v.F(derivative_reg), v.F(derivative_reg + 1));
break;
}
case 2: {
- derivates = v.ir.CompositeConstruct(v.F(derivate_reg), v.F(derivate_reg + 1),
- v.F(derivate_reg + 2), v.F(derivate_reg + 3));
+ derivatives = v.ir.CompositeConstruct(v.F(derivative_reg), v.F(derivative_reg + 1),
+ v.F(derivative_reg + 2), v.F(derivative_reg + 3));
break;
}
default:
@@ -150,9 +150,10 @@ void Impl(TranslatorVisitor& v, u64 insn, bool is_bindless) {
IR::TextureInstInfo info{};
info.type.Assign(GetType(txd.type));
- info.num_derivates.Assign(num_derivates);
+ info.num_derivatives.Assign(num_derivatives);
info.has_lod_clamp.Assign(has_lod_clamp ? 1 : 0);
- const IR::Value sample{v.ir.ImageGradient(handle, coords, derivates, offset, lod_clamp, info)};
+ const IR::Value sample{
+ v.ir.ImageGradient(handle, coords, derivatives, offset, lod_clamp, info)};
IR::Reg dest_reg{txd.dest_reg};
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
}
Optimization::CollectShaderInfoPass(env, program);
Optimization::LayerPass(program, host_info);
+ Optimization::VendorWorkaroundPass(program);
CollectInterpolationInfo(env, program);
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) {
}
}
-bool FoldDerivateYFromCorrection(IR::Inst& inst) {
+bool FoldDerivativeYFromCorrection(IR::Inst& inst) {
const IR::Value lhs_value{inst.Arg(0)};
const IR::Value rhs_value{inst.Arg(1)};
IR::Inst* const lhs_op{lhs_value.InstRecursive()};
@@ -464,7 +464,7 @@ void FoldFPMul32(IR::Inst& inst) {
if (lhs_value.IsImmediate() || rhs_value.IsImmediate()) {
return;
}
- if (FoldDerivateYFromCorrection(inst)) {
+ if (FoldDerivativeYFromCorrection(inst)) {
return;
}
IR::Inst* const lhs_op{lhs_value.InstRecursive()};
@@ -699,7 +699,7 @@ void FoldFSwizzleAdd(IR::Block& block, IR::Inst& inst) {
}
}
-bool FindGradient3DDerivates(std::array<IR::Value, 3>& results, IR::Value coord) {
+bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coord) {
if (coord.IsImmediate()) {
return false;
}
@@ -834,7 +834,7 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
IR::Inst* const inst2 = coords.InstRecursive();
std::array<std::array<IR::Value, 3>, 3> results_matrix;
for (size_t i = 0; i < 3; i++) {
- if (!FindGradient3DDerivates(results_matrix[i], inst2->Arg(i).Resolve())) {
+ if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) {
return;
}
}
@@ -852,7 +852,7 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2],
results_matrix[1][1], results_matrix[1][2]);
IR::Value derivatives_2 = ir.CompositeConstruct(results_matrix[2][1], results_matrix[2][2]);
- info.num_derivates.Assign(3);
+ info.num_derivatives.Assign(3);
IR::Value new_gradient_instruction =
ir.ImageGradient(handle, new_coords, derivatives_1, derivatives_2, lod_clamp, info);
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);
void PositionPass(Environment& env, IR::Program& program);
void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info);
void LayerPass(IR::Program& program, const HostTranslateInfo& host_info);
+void VendorWorkaroundPass(IR::Program& program);
void VerificationPass(const IR::Program& program);
// 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 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "shader_recompiler/frontend/ir/basic_block.h"
+#include "shader_recompiler/frontend/ir/ir_emitter.h"
+#include "shader_recompiler/frontend/ir/value.h"
+#include "shader_recompiler/ir_opt/passes.h"
+
+namespace Shader::Optimization {
+
+namespace {
+void AddingByteSwapsWorkaround(IR::Block& block, IR::Inst& inst) {
+ /*
+ * Workaround for an NVIDIA bug seen in Super Mario RPG
+ *
+ * We are looking for this pattern:
+ * %lhs_bfe = BitFieldUExtract %factor_a, #0, #16
+ * %lhs_mul = IMul32 %lhs_bfe, %factor_b // potentially optional?
+ * %lhs_shl = ShiftLeftLogical32 %lhs_mul, #16
+ * %rhs_bfe = BitFieldUExtract %factor_a, #16, #16
+ * %result = IAdd32 %lhs_shl, %rhs_bfe
+ *
+ * And replacing the IAdd32 with a BitwiseOr32
+ * %result = BitwiseOr32 %lhs_shl, %rhs_bfe
+ *
+ */
+ IR::Inst* const lhs_shl{inst.Arg(0).TryInstRecursive()};
+ IR::Inst* const rhs_bfe{inst.Arg(1).TryInstRecursive()};
+ if (!lhs_shl || !rhs_bfe) {
+ return;
+ }
+ if (lhs_shl->GetOpcode() != IR::Opcode::ShiftLeftLogical32 ||
+ lhs_shl->Arg(1) != IR::Value{16U}) {
+ return;
+ }
+ if (rhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract || rhs_bfe->Arg(1) != IR::Value{16U} ||
+ rhs_bfe->Arg(2) != IR::Value{16U}) {
+ return;
+ }
+ IR::Inst* const lhs_mul{lhs_shl->Arg(0).TryInstRecursive()};
+ if (!lhs_mul) {
+ return;
+ }
+ const bool lhs_mul_optional{lhs_mul->GetOpcode() == IR::Opcode::BitFieldUExtract};
+ if (lhs_mul->GetOpcode() != IR::Opcode::IMul32 &&
+ lhs_mul->GetOpcode() != IR::Opcode::BitFieldUExtract) {
+ return;
+ }
+ IR::Inst* const lhs_bfe{lhs_mul_optional ? lhs_mul : lhs_mul->Arg(0).TryInstRecursive()};
+ if (!lhs_bfe) {
+ return;
+ }
+ if (lhs_bfe->GetOpcode() != IR::Opcode::BitFieldUExtract) {
+ return;
+ }
+ if (lhs_bfe->Arg(1) != IR::Value{0U} || lhs_bfe->Arg(2) != IR::Value{16U}) {
+ return;
+ }
+ IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
+ inst.ReplaceUsesWith(ir.BitwiseOr(IR::U32{inst.Arg(0)}, IR::U32{inst.Arg(1)}));
+}
+
+} // Anonymous namespace
+
+void VendorWorkaroundPass(IR::Program& program) {
+ for (IR::Block* const block : program.post_order_blocks) {
+ for (IR::Inst& inst : block->Instructions()) {
+ switch (inst.GetOpcode()) {
+ case IR::Opcode::IAdd32:
+ AddingByteSwapsWorkaround(*block, inst);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+} // namespace Shader::Optimization
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 38d820db2..a9de9f4a9 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -43,6 +43,7 @@ struct Profile {
bool support_gl_sparse_textures{};
bool support_gl_derivative_control{};
bool support_scaled_attributes{};
+ bool support_multi_viewport{};
bool warp_size_potentially_larger_than_guest{};
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() {
.size = static_cast<u32>(size),
.buffer_id = FindBuffer(*cpu_addr, static_cast<u32>(size)),
};
- VAddr cpu_addr_start = Common::AlignDown(*cpu_addr, 64);
- VAddr cpu_addr_end = Common::AlignUp(*cpu_addr + size, 64);
- IntervalType interval{cpu_addr_start, cpu_addr_end};
- ClearDownload(interval);
- common_ranges.subtract(interval);
};
if (current_draw_indirect->include_count) {
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() {
UNIMPLEMENTED_IF_MSG(regs.clip_enable != 0, "Clipped blit enabled");
const auto& args = regs.pixels_from_memory;
- constexpr s64 null_derivate = 1ULL << 32;
+ constexpr s64 null_derivative = 1ULL << 32;
Surface src = regs.src;
const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format));
const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 &&
@@ -89,7 +89,7 @@ void Fermi2D::Blit() {
.operation = regs.operation,
.filter = args.sample_mode.filter,
.must_accelerate =
- args.du_dx != null_derivate || args.dv_dy != null_derivate || delegate_to_gpu,
+ args.du_dx != null_derivative || args.dv_dy != null_derivative || delegate_to_gpu,
.dst_x0 = args.dst_x0,
.dst_y0 = args.dst_y0,
.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() {
std::numeric_limits<u32>::max()};
const size_t byte_size = regs.index_buffer.FormatSizeInBytes();
const size_t log2_byte_size = Common::Log2Ceil64(byte_size);
- const size_t cap{GetMaxCurrentVertices() * 3 * byte_size};
+ const size_t cap{GetMaxCurrentVertices() * 4 * byte_size};
const size_t lower_cap =
std::min<size_t>(static_cast<size_t>(end_address - start_address), cap);
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:
uncommitted_operations.emplace_back(std::move(func));
}
pending_operations.emplace_back(std::move(uncommitted_operations));
- {
- std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
- QueueFence(new_fence);
- }
+ QueueFence(new_fence);
if (!delay_fence) {
func();
}
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) {
}
void GraphicsPipeline::ConfigureTransformFeedbackImpl() const {
- glTransformFeedbackAttribsNV(num_xfb_attribs, xfb_attribs.data(), GL_SEPARATE_ATTRIBS);
+ const GLenum buffer_mode =
+ num_xfb_buffers_active == 1 ? GL_INTERLEAVED_ATTRIBS : GL_SEPARATE_ATTRIBS;
+ glTransformFeedbackAttribsNV(num_xfb_attribs, xfb_attribs.data(), buffer_mode);
}
void GraphicsPipeline::GenerateTransformFeedbackState() {
@@ -567,12 +569,14 @@ void GraphicsPipeline::GenerateTransformFeedbackState() {
// when this is required.
GLint* cursor{xfb_attribs.data()};
+ num_xfb_buffers_active = 0;
for (size_t feedback = 0; feedback < Maxwell::NumTransformFeedbackBuffers; ++feedback) {
const auto& layout = key.xfb_state.layouts[feedback];
UNIMPLEMENTED_IF_MSG(layout.stride != layout.varying_count * 4, "Stride padding");
if (layout.varying_count == 0) {
continue;
}
+ num_xfb_buffers_active++;
const auto& locations = key.xfb_state.varyings[feedback];
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:
static constexpr std::size_t XFB_ENTRY_STRIDE = 3;
GLsizei num_xfb_attribs{};
+ u32 num_xfb_buffers_active{};
std::array<GLint, 128 * XFB_ENTRY_STRIDE * Maxwell::NumTransformFeedbackBuffers> xfb_attribs{};
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) {
}
{
std::scoped_lock lock{buffer_cache.mutex};
- buffer_cache.CachedWriteMemory(addr, size);
+ buffer_cache.WriteMemory(addr, size);
}
shader_cache.InvalidateRegion(addr, size);
}
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) {
const bool use_accelerated =
rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
const bool is_srgb = use_accelerated && screen_info.is_srgb;
+ RenderScreenshot(*framebuffer, use_accelerated);
- {
- std::scoped_lock lock{rasterizer.LockCaches()};
- RenderScreenshot(*framebuffer, use_accelerated);
-
- Frame* frame = present_manager.GetRenderFrame();
- blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
- scheduler.Flush(*frame->render_ready);
- present_manager.Present(frame);
- }
+ Frame* frame = present_manager.GetRenderFrame();
+ blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb);
+ scheduler.Flush(*frame->render_ready);
+ present_manager.Present(frame);
gpu.RendererFrameEndNotify();
rasterizer.TickFrame();
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 22bf8cc77..89b455bff 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -263,6 +263,22 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
info.y_negate = key.state.y_negate != 0;
return info;
}
+
+size_t GetTotalPipelineWorkers() {
+ const size_t max_core_threads =
+ std::max<size_t>(static_cast<size_t>(std::thread::hardware_concurrency()), 2ULL) - 1ULL;
+#ifdef ANDROID
+ // Leave at least a few cores free in android
+ constexpr size_t free_cores = 3ULL;
+ if (max_core_threads <= free_cores) {
+ return 1ULL;
+ }
+ return max_core_threads - free_cores;
+#else
+ return max_core_threads;
+#endif
+}
+
} // Anonymous namespace
size_t ComputePipelineCacheKey::Hash() const noexcept {
@@ -294,11 +310,8 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
texture_cache{texture_cache_}, shader_notify{shader_notify_},
use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()},
-#ifdef ANDROID
- workers(1, "VkPipelineBuilder"),
-#else
- workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "VkPipelineBuilder"),
-#endif
+ workers(device.HasBrokenParallelShaderCompiling() ? 1ULL : GetTotalPipelineWorkers(),
+ "VkPipelineBuilder"),
serialization_thread(1, "VkPipelineSerialization") {
const auto& float_control{device.FloatControlProperties()};
const VkDriverId driver_id{device.GetDriverID()};
@@ -338,6 +351,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
.support_native_ndc = device.IsExtDepthClipControlSupported(),
.support_scaled_attributes = !device.MustEmulateScaledFormats(),
+ .support_multi_viewport = device.SupportsMultiViewport(),
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp
index 66c03bf17..078777cdd 100644
--- a/src/video_core/renderer_vulkan/vk_query_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp
@@ -211,6 +211,13 @@ public:
return;
}
PauseCounter();
+ const auto driver_id = device.GetDriverID();
+ if (driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
+ driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) {
+ pending_sync.clear();
+ sync_values_stash.clear();
+ return;
+ }
sync_values_stash.clear();
sync_values_stash.emplace_back();
std::vector<HostSyncValues>* sync_values = &sync_values_stash.back();
@@ -1378,6 +1385,12 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
return true;
}
+ auto driver_id = impl->device.GetDriverID();
+ if (driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
+ driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) {
+ return true;
+ }
+
for (size_t i = 0; i < 2; i++) {
is_null[i] = !is_in_ac[i] && check_value(objects[i]->address);
}
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) {
if (!pipeline) {
return;
}
- std::scoped_lock lock{LockCaches()};
+ std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
// update engine as channel may be different.
pipeline->SetEngine(maxwell3d, gpu_memory);
pipeline->Configure(is_indexed);
@@ -621,7 +621,7 @@ void RasterizerVulkan::OnCacheInvalidation(VAddr addr, u64 size) {
}
{
std::scoped_lock lock{buffer_cache.mutex};
- buffer_cache.CachedWriteMemory(addr, size);
+ buffer_cache.WriteMemory(addr, size);
}
pipeline_cache.InvalidateRegion(addr, size);
}
@@ -710,7 +710,6 @@ void RasterizerVulkan::TiledCacheBarrier() {
}
void RasterizerVulkan::FlushCommands() {
- std::scoped_lock lock{LockCaches()};
if (draw_counter == 0) {
return;
}
@@ -808,7 +807,6 @@ void RasterizerVulkan::FlushWork() {
if ((++draw_counter & 7) != 7) {
return;
}
- std::scoped_lock lock{LockCaches()};
if (draw_counter < DRAWS_TO_DISPATCH) {
// Send recorded tasks to the worker thread
scheduler.DispatchWork();
@@ -1507,7 +1505,7 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {
CreateChannel(channel);
{
- std::scoped_lock lock{LockCaches()};
+ std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
texture_cache.CreateChannel(channel);
buffer_cache.CreateChannel(channel);
}
@@ -1520,7 +1518,7 @@ void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) {
const s32 channel_id = channel.bind_id;
BindToChannel(channel_id);
{
- std::scoped_lock lock{LockCaches()};
+ std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
texture_cache.BindToChannel(channel_id);
buffer_cache.BindToChannel(channel_id);
}
@@ -1533,7 +1531,7 @@ void RasterizerVulkan::BindChannel(Tegra::Control::ChannelState& channel) {
void RasterizerVulkan::ReleaseChannel(s32 channel_id) {
EraseChannel(channel_id);
{
- std::scoped_lock lock{LockCaches()};
+ std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
texture_cache.EraseChannel(channel_id);
buffer_cache.EraseChannel(channel_id);
}
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:
void ReleaseChannel(s32 channel_id) override;
- std::scoped_lock<std::recursive_mutex, std::recursive_mutex> LockCaches() {
- return std::scoped_lock{buffer_cache.mutex, texture_cache.mutex};
- }
-
private:
static constexpr size_t MAX_TEXTURES = 192;
static constexpr size_t MAX_IMAGES = 48;
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index e518756d2..6900b8ffa 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -635,6 +635,12 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
has_broken_cube_compatibility = true;
}
}
+ if (is_qualcomm) {
+ const u32 version = (properties.properties.driverVersion << 3) >> 3;
+ if (version < VK_MAKE_API_VERSION(0, 255, 615, 512)) {
+ has_broken_parallel_compiling = true;
+ }
+ }
if (extensions.sampler_filter_minmax && is_amd) {
// Disable ext_sampler_filter_minmax on AMD GCN4 and lower as it is broken.
if (!features.shader_float16_int8.shaderFloat16) {
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index b213ed7dd..4f3846345 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -102,6 +102,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME) \
+ EXTENSION_NAME(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_4444_FORMATS_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME) \
EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \
@@ -599,6 +600,11 @@ public:
return has_broken_cube_compatibility;
}
+ /// Returns true if parallel shader compiling has issues with the current driver.
+ bool HasBrokenParallelShaderCompiling() const {
+ return has_broken_parallel_compiling;
+ }
+
/// Returns the vendor name reported from Vulkan.
std::string_view GetVendorName() const {
return properties.driver.driverName;
@@ -663,6 +669,10 @@ public:
return supports_conditional_barriers;
}
+ bool SupportsMultiViewport() const {
+ return features2.features.multiViewport;
+ }
+
[[nodiscard]] static constexpr bool CheckBrokenCompute(VkDriverId driver_id,
u32 driver_version) {
if (driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
@@ -794,6 +804,7 @@ private:
bool is_non_gpu{}; ///< Is SoftwareRasterizer, FPGA, non-GPU device.
bool has_broken_compute{}; ///< Compute shaders can cause crashes
bool has_broken_cube_compatibility{}; ///< Has broken cube compatibility bit
+ bool has_broken_parallel_compiling{}; ///< Has broken parallel shader compiling.
bool has_renderdoc{}; ///< Has RenderDoc attached
bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
bool supports_d24_depth{}; ///< Supports D24 depth buffers.
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 33e1fb663..181b2817c 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -252,6 +252,7 @@ file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
if (ENABLE_QT_TRANSLATION)
set(YUZU_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
+ option(WORKAROUND_BROKEN_LUPDATE "Run lupdate directly through CMake if Qt's convenience wrappers don't work" OFF)
# Update source TS file if enabled
if (GENERATE_QT_TRANSLATION)
@@ -259,19 +260,51 @@ if (ENABLE_QT_TRANSLATION)
# these calls to qt_create_translation also creates a rule to generate en.qm which conflicts with providing english plurals
# so we have to set a OUTPUT_LOCATION so that we don't have multiple rules to generate en.qm
set_source_files_properties(${YUZU_QT_LANGUAGES}/en.ts PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
- qt_create_translation(QM_FILES
- ${SRCS}
- ${UIS}
- ${YUZU_QT_LANGUAGES}/en.ts
- OPTIONS
- -source-language en_US
- -target-language en_US
- )
+ if (WORKAROUND_BROKEN_LUPDATE)
+ add_custom_command(OUTPUT ${YUZU_QT_LANGUAGES}/en.ts
+ COMMAND lupdate
+ -source-language en_US
+ -target-language en_US
+ ${SRCS}
+ ${UIS}
+ -ts ${YUZU_QT_LANGUAGES}/en.ts
+ DEPENDS
+ ${SRCS}
+ ${UIS}
+ WORKING_DIRECTORY
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+ else()
+ qt_create_translation(QM_FILES
+ ${SRCS}
+ ${UIS}
+ ${YUZU_QT_LANGUAGES}/en.ts
+ OPTIONS
+ -source-language en_US
+ -target-language en_US
+ )
+ endif()
# Generate plurals into dist/english_plurals/generated_en.ts so it can be used to revise dist/english_plurals/en.ts
set(GENERATED_PLURALS_FILE ${PROJECT_SOURCE_DIR}/dist/english_plurals/generated_en.ts)
set_source_files_properties(${GENERATED_PLURALS_FILE} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/plurals")
- qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
+ if (WORKAROUND_BROKEN_LUPDATE)
+ add_custom_command(OUTPUT ${GENERATED_PLURALS_FILE}
+ COMMAND lupdate
+ -source-language en_US
+ -target-language en_US
+ ${SRCS}
+ ${UIS}
+ -ts ${GENERATED_PLURALS_FILE}
+ DEPENDS
+ ${SRCS}
+ ${UIS}
+ WORKING_DIRECTORY
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+ else()
+ qt_create_translation(QM_FILES ${SRCS} ${UIS} ${GENERATED_PLURALS_FILE} OPTIONS -pluralonly -source-language en_US -target-language en_US)
+ endif()
add_custom_target(translation ALL DEPENDS ${YUZU_QT_LANGUAGES}/en.ts ${GENERATED_PLURALS_FILE})
endif()
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 @@
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/npad.h"
-#include "core/hle/service/hid/hid.h"
#include "core/hle/service/sm/sm.h"
#include "ui_qt_controller.h"
#include "yuzu/applets/qt_controller.h"
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 42bbb2964..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
Qt::Key_G, Qt::Key_Q, Qt::Key_E, Qt::Key_R, Qt::Key_T,
Qt::Key_M, Qt::Key_N, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right,
Qt::Key_Down, Qt::Key_Q, Qt::Key_E, 0, 0,
+ Qt::Key_Q, Qt::Key_E,
};
const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = {
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
setFocusPolicy(Qt::ClickFocus);
button_map = {
- ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
- ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
- ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
- ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
- ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
+ ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY,
+ ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR,
+ ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus,
+ ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown,
+ ui->buttonSLLeft, ui->buttonSRLeft, ui->buttonHome, ui->buttonScreenshot,
+ ui->buttonSLRight, ui->buttonSRRight,
};
analog_map_buttons = {{
@@ -1181,10 +1182,13 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
// List of all the widgets that will be hidden by any of the following layouts that need
// "unhidden" after the controller type changes
- const std::array<QWidget*, 11> layout_show = {
- ui->buttonShoulderButtonsSLSR,
+ const std::array<QWidget*, 14> layout_show = {
+ ui->buttonShoulderButtonsSLSRLeft,
+ ui->buttonShoulderButtonsSLSRRight,
ui->horizontalSpacerShoulderButtonsWidget,
ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->horizontalSpacerShoulderButtonsWidget3,
+ ui->horizontalSpacerShoulderButtonsWidget4,
ui->buttonShoulderButtonsLeft,
ui->buttonMiscButtonsMinusScreenshot,
ui->bottomLeft,
@@ -1202,16 +1206,19 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
std::vector<QWidget*> layout_hidden;
switch (layout) {
case Core::HID::NpadStyleIndex::ProController:
- case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::Handheld:
layout_hidden = {
- ui->buttonShoulderButtonsSLSR,
+ ui->buttonShoulderButtonsSLSRLeft,
+ ui->buttonShoulderButtonsSLSRRight,
ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->horizontalSpacerShoulderButtonsWidget4,
};
break;
case Core::HID::NpadStyleIndex::JoyconLeft:
layout_hidden = {
+ ui->buttonShoulderButtonsSLSRRight,
ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->horizontalSpacerShoulderButtonsWidget3,
ui->buttonShoulderButtonsRight,
ui->buttonMiscButtonsPlusHome,
ui->bottomRight,
@@ -1219,16 +1226,17 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
break;
case Core::HID::NpadStyleIndex::JoyconRight:
layout_hidden = {
- ui->horizontalSpacerShoulderButtonsWidget,
- ui->buttonShoulderButtonsLeft,
- ui->buttonMiscButtonsMinusScreenshot,
- ui->bottomLeft,
+ ui->buttonShoulderButtonsSLSRLeft, ui->horizontalSpacerShoulderButtonsWidget,
+ ui->horizontalSpacerShoulderButtonsWidget4, ui->buttonShoulderButtonsLeft,
+ ui->buttonMiscButtonsMinusScreenshot, ui->bottomLeft,
};
break;
case Core::HID::NpadStyleIndex::GameCube:
layout_hidden = {
- ui->buttonShoulderButtonsSLSR,
+ ui->buttonShoulderButtonsSLSRLeft,
+ ui->buttonShoulderButtonsSLSRRight,
ui->horizontalSpacerShoulderButtonsWidget2,
+ ui->horizontalSpacerShoulderButtonsWidget4,
ui->buttonMiscButtonsMinusGroup,
ui->buttonMiscButtonsScreenshotGroup,
};
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 @@
<property name="spacing">
<number>3</number>
</property>
+ <item>
+ <widget class="QWidget" name="buttonShoulderButtonsSLSRLeft" native="true">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRLeftVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSLLeftGroup">
+ <property name="title">
+ <string>SL</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLLeftVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSLLeft">
+ <property name="minimumSize">
+ <size>
+ <width>68</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>68</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 68px;</string>
+ </property>
+ <property name="text">
+ <string>SL</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSRLeftGroup">
+ <property name="title">
+ <string>SR</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSRLeftVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSRLeft">
+ <property name="minimumSize">
+ <size>
+ <width>68</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>68</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 68px;</string>
+ </property>
+ <property name="text">
+ <string>SR</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalSpacerShoulderButtonsWidget4" native="true">
+ <layout class="QHBoxLayout" name="horizontalSpacerShoulderButtonsWidget4Layout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacerShoulderButtons5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
<item>
<widget class="QWidget" name="buttonShoulderButtonsLeft" native="true">
<layout class="QVBoxLayout" name="buttonShoulderButtonsLeftVerticalLayout">
@@ -1830,125 +1983,125 @@
</layout>
</widget>
</item>
- <item>
- <widget class="QWidget" name="buttonShoulderButtonsSLSR" native="true">
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRVerticalLayout">
- <property name="spacing">
- <number>0</number>
- </property>
- <property name="leftMargin">
- <number>0</number>
- </property>
- <property name="topMargin">
- <number>0</number>
- </property>
- <property name="rightMargin">
- <number>0</number>
- </property>
- <property name="bottomMargin">
- <number>0</number>
- </property>
- <item alignment="Qt::AlignHCenter">
- <widget class="QGroupBox" name="buttonShoulderButtonsSLGroup">
- <property name="title">
- <string>SL</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSLVerticalLayout">
- <property name="spacing">
- <number>3</number>
- </property>
- <property name="leftMargin">
- <number>3</number>
- </property>
- <property name="topMargin">
- <number>3</number>
- </property>
- <property name="rightMargin">
- <number>3</number>
- </property>
- <property name="bottomMargin">
- <number>3</number>
- </property>
- <item>
- <widget class="QPushButton" name="buttonSL">
- <property name="minimumSize">
- <size>
- <width>68</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>68</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true">min-width: 68px;</string>
- </property>
- <property name="text">
- <string>SL</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item alignment="Qt::AlignHCenter">
- <widget class="QGroupBox" name="buttonShoulderButtonsSRGroup">
- <property name="title">
- <string>SR</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- <layout class="QVBoxLayout" name="buttonShoulderButtonsSRVerticalLayout">
- <property name="spacing">
- <number>3</number>
- </property>
- <property name="leftMargin">
- <number>3</number>
- </property>
- <property name="topMargin">
- <number>3</number>
- </property>
- <property name="rightMargin">
- <number>3</number>
- </property>
- <property name="bottomMargin">
- <number>3</number>
- </property>
- <item>
- <widget class="QPushButton" name="buttonSR">
- <property name="minimumSize">
- <size>
- <width>68</width>
- <height>0</height>
- </size>
- </property>
- <property name="maximumSize">
- <size>
- <width>68</width>
- <height>16777215</height>
- </size>
- </property>
- <property name="styleSheet">
- <string notr="true">min-width: 68px;</string>
- </property>
- <property name="text">
- <string>SR</string>
- </property>
- </widget>
- </item>
+ <item>
+ <widget class="QWidget" name="buttonShoulderButtonsSLSRRight" native="true">
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLSRRightVerticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSLRightGroup">
+ <property name="title">
+ <string>SL</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSLRightVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSLRight">
+ <property name="minimumSize">
+ <size>
+ <width>68</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>68</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 68px;</string>
+ </property>
+ <property name="text">
+ <string>SL</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignHCenter">
+ <widget class="QGroupBox" name="buttonShoulderButtonsSRRightGroup">
+ <property name="title">
+ <string>SR</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <layout class="QVBoxLayout" name="buttonShoulderButtonsSRRightVerticalLayout">
+ <property name="spacing">
+ <number>3</number>
+ </property>
+ <property name="leftMargin">
+ <number>3</number>
+ </property>
+ <property name="topMargin">
+ <number>3</number>
+ </property>
+ <property name="rightMargin">
+ <number>3</number>
+ </property>
+ <property name="bottomMargin">
+ <number>3</number>
+ </property>
+ <item>
+ <widget class="QPushButton" name="buttonSRRight">
+ <property name="minimumSize">
+ <size>
+ <width>68</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>68</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">min-width: 68px;</string>
+ </property>
+ <property name="text">
+ <string>SR</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
</layout>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
+ </widget>
+ </item>
</layout>
</item>
<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)
// Sideview SL and SR buttons
button_color = colors.slider_button;
- DrawRoundButton(p, center + QPoint(59, 52), button_values[SR], 5, 12, Direction::Left);
- DrawRoundButton(p, center + QPoint(59, -69), button_values[SL], 5, 12, Direction::Left);
+ DrawRoundButton(p, center + QPoint(59, 52), button_values[SRLeft], 5, 12, Direction::Left);
+ DrawRoundButton(p, center + QPoint(59, -69), button_values[SLLeft], 5, 12, Direction::Left);
DrawLeftBody(p, center);
@@ -353,8 +353,10 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center)
// SR and SL buttons
p.setPen(colors.outline);
button_color = colors.slider_button;
- DrawRoundButton(p, center + QPoint(155, 52), button_values[SR], 5.2f, 12, Direction::None, 4);
- DrawRoundButton(p, center + QPoint(155, -69), button_values[SL], 5.2f, 12, Direction::None, 4);
+ DrawRoundButton(p, center + QPoint(155, 52), button_values[SRLeft], 5.2f, 12, Direction::None,
+ 4);
+ DrawRoundButton(p, center + QPoint(155, -69), button_values[SLLeft], 5.2f, 12, Direction::None,
+ 4);
// SR and SL text
p.setPen(colors.transparent);
@@ -428,8 +430,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
// Sideview SL and SR buttons
button_color = colors.slider_button;
- DrawRoundButton(p, center + QPoint(-59, 52), button_values[SL], 5, 11, Direction::Right);
- DrawRoundButton(p, center + QPoint(-59, -69), button_values[SR], 5, 11, Direction::Right);
+ DrawRoundButton(p, center + QPoint(-59, 52), button_values[SLRight], 5, 11,
+ Direction::Right);
+ DrawRoundButton(p, center + QPoint(-59, -69), button_values[SRRight], 5, 11,
+ Direction::Right);
DrawRightBody(p, center);
@@ -484,8 +488,10 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center
// SR and SL buttons
p.setPen(colors.outline);
button_color = colors.slider_button;
- DrawRoundButton(p, center + QPoint(-155, 52), button_values[SL], 5, 12, Direction::None, 4.0f);
- DrawRoundButton(p, center + QPoint(-155, -69), button_values[SR], 5, 12, Direction::None, 4.0f);
+ DrawRoundButton(p, center + QPoint(-155, 52), button_values[SLRight], 5, 12, Direction::None,
+ 4.0f);
+ DrawRoundButton(p, center + QPoint(-155, -69), button_values[SRRight], 5, 12, Direction::None,
+ 4.0f);
// SR and SL text
p.setPen(colors.transparent);
@@ -557,6 +563,19 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
DrawRoundButton(p, center + QPoint(-154, -72), button_values[Minus], 7, 4, Direction::Up,
1);
+ // Left SR and SL sideview buttons
+ button_color = colors.slider_button;
+ DrawRoundButton(p, center + QPoint(-20, -62), button_values[SLLeft], 4, 11,
+ Direction::Left);
+ DrawRoundButton(p, center + QPoint(-20, 47), button_values[SRLeft], 4, 11, Direction::Left);
+
+ // Right SR and SL sideview buttons
+ button_color = colors.slider_button;
+ DrawRoundButton(p, center + QPoint(20, 47), button_values[SLRight], 4, 11,
+ Direction::Right);
+ DrawRoundButton(p, center + QPoint(20, -62), button_values[SRRight], 4, 11,
+ Direction::Right);
+
DrawDualBody(p, center);
// Right trigger top view
@@ -1792,16 +1811,6 @@ void PlayerControlPreview::DrawDualBody(QPainter& p, const QPointF center) {
p.setBrush(colors.right);
DrawPolygon(p, qright_joycon_topview);
- // Right SR and SL sideview buttons
- p.setPen(colors.outline);
- p.setBrush(colors.slider_button);
- DrawRoundRectangle(p, center + QPoint(19, 47), 7, 22, 1);
- DrawRoundRectangle(p, center + QPoint(19, -62), 7, 22, 1);
-
- // Left SR and SL sideview buttons
- DrawRoundRectangle(p, center + QPoint(-19, 47), 7, 22, 1);
- DrawRoundRectangle(p, center + QPoint(-19, -62), 7, 22, 1);
-
// Right Sideview body
p.setBrush(colors.slider);
DrawPolygon(p, qright_joycon_slider);
diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp
index 1434b1a56..a7b5def32 100644
--- a/src/yuzu/configuration/shared_translation.cpp
+++ b/src/yuzu/configuration/shared_translation.cpp
@@ -1,17 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "common/time_zone.h"
#include "yuzu/configuration/shared_translation.h"
#include <map>
#include <memory>
#include <tuple>
#include <utility>
+#include <QCoreApplication>
#include <QWidget>
#include "common/settings.h"
#include "common/settings_enums.h"
#include "common/settings_setting.h"
+#include "common/time_zone.h"
#include "yuzu/uisettings.h"
namespace ConfigurationShared {
@@ -21,123 +22,135 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
const auto& tr = [parent](const char* text) -> QString { return parent->tr(text); };
#define INSERT(SETTINGS, ID, NAME, TOOLTIP) \
- translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{tr((NAME)), tr((TOOLTIP))}})
+ translations->insert(std::pair{SETTINGS::values.ID.Id(), std::pair{(NAME), (TOOLTIP)}})
// A setting can be ignored by giving it a blank name
// Audio
- INSERT(Settings, sink_id, "Output Engine:", "");
- INSERT(Settings, audio_output_device_id, "Output Device:", "");
- INSERT(Settings, audio_input_device_id, "Input Device:", "");
- INSERT(Settings, audio_muted, "Mute audio", "");
- INSERT(Settings, volume, "Volume:", "");
- INSERT(Settings, dump_audio_commands, "", "");
- INSERT(UISettings, mute_when_in_background, "Mute audio when in background", "");
+ INSERT(Settings, sink_id, tr("Output Engine:"), QStringLiteral());
+ INSERT(Settings, audio_output_device_id, tr("Output Device:"), QStringLiteral());
+ INSERT(Settings, audio_input_device_id, tr("Input Device:"), QStringLiteral());
+ INSERT(Settings, audio_muted, tr("Mute audio"), QStringLiteral());
+ INSERT(Settings, volume, tr("Volume:"), QStringLiteral());
+ INSERT(Settings, dump_audio_commands, QStringLiteral(), QStringLiteral());
+ INSERT(UISettings, mute_when_in_background, tr("Mute audio when in background"),
+ QStringLiteral());
// Core
- INSERT(Settings, use_multi_core, "Multicore CPU Emulation", "");
- INSERT(Settings, memory_layout_mode, "Memory Layout", "");
- INSERT(Settings, use_speed_limit, "", "");
- INSERT(Settings, speed_limit, "Limit Speed Percent", "");
+ INSERT(Settings, use_multi_core, tr("Multicore CPU Emulation"), QStringLiteral());
+ INSERT(Settings, memory_layout_mode, tr("Memory Layout"), QStringLiteral());
+ INSERT(Settings, use_speed_limit, QStringLiteral(), QStringLiteral());
+ INSERT(Settings, speed_limit, tr("Limit Speed Percent"), QStringLiteral());
// Cpu
- INSERT(Settings, cpu_accuracy, "Accuracy:", "");
+ INSERT(Settings, cpu_accuracy, tr("Accuracy:"), QStringLiteral());
// Cpu Debug
// Cpu Unsafe
- INSERT(Settings, cpuopt_unsafe_unfuse_fma,
- "Unfuse FMA (improve performance on CPUs without FMA)",
- "This option improves speed by reducing accuracy of fused-multiply-add instructions on "
- "CPUs without native FMA support.");
- INSERT(Settings, cpuopt_unsafe_reduce_fp_error, "Faster FRSQRTE and FRECPE",
- "This option improves the speed of some approximate floating-point functions by using "
- "less accurate native approximations.");
- INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr, "Faster ASIMD instructions (32 bits only)",
- "This option improves the speed of 32 bits ASIMD floating-point functions by running "
- "with incorrect rounding modes.");
- INSERT(Settings, cpuopt_unsafe_inaccurate_nan, "Inaccurate NaN handling",
- "This option improves speed by removing NaN checking. Please note this also reduces "
- "accuracy of certain floating-point instructions.");
INSERT(
- Settings, cpuopt_unsafe_fastmem_check, "Disable address space checks",
- "This option improves speed by eliminating a safety check before every memory read/write "
- "in guest. Disabling it may allow a game to read/write the emulator's memory.");
- INSERT(Settings, cpuopt_unsafe_ignore_global_monitor, "Ignore global monitor",
- "This option improves speed by relying only on the semantics of cmpxchg to ensure "
+ Settings, cpuopt_unsafe_unfuse_fma,
+ tr("Unfuse FMA (improve performance on CPUs without FMA)"),
+ tr("This option improves speed by reducing accuracy of fused-multiply-add instructions on "
+ "CPUs without native FMA support."));
+ INSERT(
+ Settings, cpuopt_unsafe_reduce_fp_error, tr("Faster FRSQRTE and FRECPE"),
+ tr("This option improves the speed of some approximate floating-point functions by using "
+ "less accurate native approximations."));
+ INSERT(Settings, cpuopt_unsafe_ignore_standard_fpcr,
+ tr("Faster ASIMD instructions (32 bits only)"),
+ tr("This option improves the speed of 32 bits ASIMD floating-point functions by running "
+ "with incorrect rounding modes."));
+ INSERT(Settings, cpuopt_unsafe_inaccurate_nan, tr("Inaccurate NaN handling"),
+ tr("This option improves speed by removing NaN checking. Please note this also reduces "
+ "accuracy of certain floating-point instructions."));
+ INSERT(Settings, cpuopt_unsafe_fastmem_check, tr("Disable address space checks"),
+ tr("This option improves speed by eliminating a safety check before every memory "
+ "read/write "
+ "in guest. Disabling it may allow a game to read/write the emulator's memory."));
+ INSERT(
+ Settings, cpuopt_unsafe_ignore_global_monitor, tr("Ignore global monitor"),
+ tr("This option improves speed by relying only on the semantics of cmpxchg to ensure "
"safety of exclusive access instructions. Please note this may result in deadlocks and "
- "other race conditions.");
+ "other race conditions."));
// Renderer
- INSERT(Settings, renderer_backend, "API:", "");
- INSERT(Settings, vulkan_device, "Device:", "");
- INSERT(Settings, shader_backend, "Shader Backend:", "");
- INSERT(Settings, resolution_setup, "Resolution:", "");
- INSERT(Settings, scaling_filter, "Window Adapting Filter:", "");
- INSERT(Settings, fsr_sharpening_slider, "FSR Sharpness:", "");
- INSERT(Settings, anti_aliasing, "Anti-Aliasing Method:", "");
- INSERT(Settings, fullscreen_mode, "Fullscreen Mode:", "");
- INSERT(Settings, aspect_ratio, "Aspect Ratio:", "");
- INSERT(Settings, use_disk_shader_cache, "Use disk pipeline cache", "");
- INSERT(Settings, use_asynchronous_gpu_emulation, "Use asynchronous GPU emulation", "");
- INSERT(Settings, nvdec_emulation, "NVDEC emulation:", "");
- INSERT(Settings, accelerate_astc, "ASTC Decoding Method:", "");
- INSERT(Settings, astc_recompression, "ASTC Recompression Method:", "");
- INSERT(Settings, vsync_mode, "VSync Mode:",
- "FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
+ INSERT(Settings, renderer_backend, tr("API:"), QStringLiteral());
+ INSERT(Settings, vulkan_device, tr("Device:"), QStringLiteral());
+ INSERT(Settings, shader_backend, tr("Shader Backend:"), QStringLiteral());
+ INSERT(Settings, resolution_setup, tr("Resolution:"), QStringLiteral());
+ INSERT(Settings, scaling_filter, tr("Window Adapting Filter:"), QStringLiteral());
+ INSERT(Settings, fsr_sharpening_slider, tr("FSR Sharpness:"), QStringLiteral());
+ INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), QStringLiteral());
+ INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), QStringLiteral());
+ INSERT(Settings, aspect_ratio, tr("Aspect Ratio:"), QStringLiteral());
+ INSERT(Settings, use_disk_shader_cache, tr("Use disk pipeline cache"), QStringLiteral());
+ INSERT(Settings, use_asynchronous_gpu_emulation, tr("Use asynchronous GPU emulation"),
+ QStringLiteral());
+ INSERT(Settings, nvdec_emulation, tr("NVDEC emulation:"), QStringLiteral());
+ INSERT(Settings, accelerate_astc, tr("ASTC Decoding Method:"), QStringLiteral());
+ INSERT(Settings, astc_recompression, tr("ASTC Recompression Method:"), QStringLiteral());
+ INSERT(
+ Settings, vsync_mode, tr("VSync Mode:"),
+ tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
"refresh rate.\nFIFO Relaxed is similar to FIFO but allows tearing as it recovers from "
"a slow down.\nMailbox can have lower latency than FIFO and does not tear but may drop "
"frames.\nImmediate (no synchronization) just presents whatever is available and can "
- "exhibit tearing.");
- INSERT(Settings, bg_red, "", "");
- INSERT(Settings, bg_green, "", "");
- INSERT(Settings, bg_blue, "", "");
+ "exhibit tearing."));
+ INSERT(Settings, bg_red, QStringLiteral(), QStringLiteral());
+ INSERT(Settings, bg_green, QStringLiteral(), QStringLiteral());
+ INSERT(Settings, bg_blue, QStringLiteral(), QStringLiteral());
// Renderer (Advanced Graphics)
- INSERT(Settings, async_presentation, "Enable asynchronous presentation (Vulkan only)", "");
- INSERT(Settings, renderer_force_max_clock, "Force maximum clocks (Vulkan only)",
- "Runs work in the background while waiting for graphics commands to keep the GPU from "
- "lowering its clock speed.");
- INSERT(Settings, max_anisotropy, "Anisotropic Filtering:", "");
- INSERT(Settings, gpu_accuracy, "Accuracy Level:", "");
- INSERT(Settings, use_asynchronous_shaders, "Use asynchronous shader building (Hack)",
- "Enables asynchronous shader compilation, which may reduce shader stutter. This feature "
- "is experimental.");
- INSERT(Settings, use_fast_gpu_time, "Use Fast GPU Time (Hack)",
- "Enables Fast GPU Time. This option will force most games to run at their highest "
- "native resolution.");
- INSERT(Settings, use_vulkan_driver_pipeline_cache, "Use Vulkan pipeline cache",
- "Enables GPU vendor-specific pipeline cache. This option can improve shader loading "
- "time significantly in cases where the Vulkan driver does not store pipeline cache "
- "files internally.");
- INSERT(Settings, enable_compute_pipelines, "Enable Compute Pipelines (Intel Vulkan Only)",
- "Enable compute pipelines, required by some games.\nThis setting only exists for Intel "
+ INSERT(Settings, async_presentation, tr("Enable asynchronous presentation (Vulkan only)"),
+ QStringLiteral());
+ INSERT(
+ Settings, renderer_force_max_clock, tr("Force maximum clocks (Vulkan only)"),
+ tr("Runs work in the background while waiting for graphics commands to keep the GPU from "
+ "lowering its clock speed."));
+ INSERT(Settings, max_anisotropy, tr("Anisotropic Filtering:"), QStringLiteral());
+ INSERT(Settings, gpu_accuracy, tr("Accuracy Level:"), QStringLiteral());
+ INSERT(
+ Settings, use_asynchronous_shaders, tr("Use asynchronous shader building (Hack)"),
+ tr("Enables asynchronous shader compilation, which may reduce shader stutter. This feature "
+ "is experimental."));
+ INSERT(Settings, use_fast_gpu_time, tr("Use Fast GPU Time (Hack)"),
+ tr("Enables Fast GPU Time. This option will force most games to run at their highest "
+ "native resolution."));
+ INSERT(Settings, use_vulkan_driver_pipeline_cache, tr("Use Vulkan pipeline cache"),
+ tr("Enables GPU vendor-specific pipeline cache. This option can improve shader loading "
+ "time significantly in cases where the Vulkan driver does not store pipeline cache "
+ "files internally."));
+ INSERT(
+ Settings, enable_compute_pipelines, tr("Enable Compute Pipelines (Intel Vulkan Only)"),
+ tr("Enable compute pipelines, required by some games.\nThis setting only exists for Intel "
"proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled "
- "on all other drivers.");
- INSERT(Settings, use_reactive_flushing, "Enable Reactive Flushing",
- "Uses reactive flushing instead of predictive flushing, allowing more accurate memory "
- "syncing.");
- INSERT(Settings, use_video_framerate, "Sync to framerate of video playback",
- "Run the game at normal speed during video playback, even when the framerate is "
- "unlocked.");
- INSERT(Settings, barrier_feedback_loops, "Barrier feedback loops",
- "Improves rendering of transparency effects in specific games.");
+ "on all other drivers."));
+ INSERT(
+ Settings, use_reactive_flushing, tr("Enable Reactive Flushing"),
+ tr("Uses reactive flushing instead of predictive flushing, allowing more accurate memory "
+ "syncing."));
+ INSERT(Settings, use_video_framerate, tr("Sync to framerate of video playback"),
+ tr("Run the game at normal speed during video playback, even when the framerate is "
+ "unlocked."));
+ INSERT(Settings, barrier_feedback_loops, tr("Barrier feedback loops"),
+ tr("Improves rendering of transparency effects in specific games."));
// Renderer (Debug)
// System
- INSERT(Settings, rng_seed, "RNG Seed", "");
- INSERT(Settings, rng_seed_enabled, "", "");
- INSERT(Settings, device_name, "Device Name", "");
- INSERT(Settings, custom_rtc, "Custom RTC", "");
- INSERT(Settings, custom_rtc_enabled, "", "");
- INSERT(Settings, language_index,
- "Language:", "Note: this can be overridden when region setting is auto-select");
- INSERT(Settings, region_index, "Region:", "");
- INSERT(Settings, time_zone_index, "Time Zone:", "");
- INSERT(Settings, sound_index, "Sound Output Mode:", "");
- INSERT(Settings, use_docked_mode, "Console Mode:", "");
- INSERT(Settings, current_user, "", "");
+ INSERT(Settings, rng_seed, tr("RNG Seed"), QStringLiteral());
+ INSERT(Settings, rng_seed_enabled, QStringLiteral(), QStringLiteral());
+ INSERT(Settings, device_name, tr("Device Name"), QStringLiteral());
+ INSERT(Settings, custom_rtc, tr("Custom RTC"), QStringLiteral());
+ INSERT(Settings, custom_rtc_enabled, QStringLiteral(), QStringLiteral());
+ INSERT(Settings, language_index, tr("Language:"),
+ tr("Note: this can be overridden when region setting is auto-select"));
+ INSERT(Settings, region_index, tr("Region:"), QStringLiteral());
+ INSERT(Settings, time_zone_index, tr("Time Zone:"), QStringLiteral());
+ INSERT(Settings, sound_index, tr("Sound Output Mode:"), QStringLiteral());
+ INSERT(Settings, use_docked_mode, tr("Console Mode:"), QStringLiteral());
+ INSERT(Settings, current_user, QStringLiteral(), QStringLiteral());
// Controls
@@ -154,11 +167,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) {
// Ui
// Ui General
- INSERT(UISettings, select_user_on_boot, "Prompt for user on game boot", "");
- INSERT(UISettings, pause_when_in_background, "Pause emulation when in background", "");
- INSERT(UISettings, confirm_before_stopping, "Confirm before stopping emulation", "");
- INSERT(UISettings, hide_mouse, "Hide mouse on inactivity", "");
- INSERT(UISettings, controller_applet_disabled, "Disable controller applet", "");
+ INSERT(UISettings, select_user_on_boot, tr("Prompt for user on game boot"), QStringLiteral());
+ INSERT(UISettings, pause_when_in_background, tr("Pause emulation when in background"),
+ QStringLiteral());
+ INSERT(UISettings, confirm_before_stopping, tr("Confirm before stopping emulation"),
+ QStringLiteral());
+ INSERT(UISettings, hide_mouse, tr("Hide mouse on inactivity"), QStringLiteral());
+ INSERT(UISettings, controller_applet_disabled, tr("Disable controller applet"),
+ QStringLiteral());
// Ui Debugging
@@ -178,140 +194,141 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
return parent->tr(text, context);
};
-#define PAIR(ENUM, VALUE, TRANSLATION) \
- { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION) }
-#define CTX_PAIR(ENUM, VALUE, TRANSLATION, CONTEXT) \
- { static_cast<u32>(Settings::ENUM::VALUE), tr(TRANSLATION, CONTEXT) }
+#define PAIR(ENUM, VALUE, TRANSLATION) {static_cast<u32>(Settings::ENUM::VALUE), (TRANSLATION)}
// Intentionally skipping VSyncMode to let the UI fill that one out
translations->insert({Settings::EnumMetadata<Settings::AstcDecodeMode>::Index(),
{
- PAIR(AstcDecodeMode, Cpu, "CPU"),
- PAIR(AstcDecodeMode, Gpu, "GPU"),
- PAIR(AstcDecodeMode, CpuAsynchronous, "CPU Asynchronous"),
- }});
- translations->insert({Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
- {
- PAIR(AstcRecompression, Uncompressed, "Uncompressed (Best quality)"),
- PAIR(AstcRecompression, Bc1, "BC1 (Low quality)"),
- PAIR(AstcRecompression, Bc3, "BC3 (Medium quality)"),
+ PAIR(AstcDecodeMode, Cpu, tr("CPU")),
+ PAIR(AstcDecodeMode, Gpu, tr("GPU")),
+ PAIR(AstcDecodeMode, CpuAsynchronous, tr("CPU Asynchronous")),
}});
+ translations->insert(
+ {Settings::EnumMetadata<Settings::AstcRecompression>::Index(),
+ {
+ PAIR(AstcRecompression, Uncompressed, tr("Uncompressed (Best quality)")),
+ PAIR(AstcRecompression, Bc1, tr("BC1 (Low quality)")),
+ PAIR(AstcRecompression, Bc3, tr("BC3 (Medium quality)")),
+ }});
translations->insert({Settings::EnumMetadata<Settings::RendererBackend>::Index(),
{
#ifdef HAS_OPENGL
- PAIR(RendererBackend, OpenGL, "OpenGL"),
+ PAIR(RendererBackend, OpenGL, tr("OpenGL")),
#endif
- PAIR(RendererBackend, Vulkan, "Vulkan"),
- PAIR(RendererBackend, Null, "Null"),
- }});
- translations->insert({Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
- {
- PAIR(ShaderBackend, Glsl, "GLSL"),
- PAIR(ShaderBackend, Glasm, "GLASM (Assembly Shaders, NVIDIA Only)"),
- PAIR(ShaderBackend, SpirV, "SPIR-V (Experimental, Mesa Only)"),
+ PAIR(RendererBackend, Vulkan, tr("Vulkan")),
+ PAIR(RendererBackend, Null, tr("Null")),
}});
+ translations->insert(
+ {Settings::EnumMetadata<Settings::ShaderBackend>::Index(),
+ {
+ PAIR(ShaderBackend, Glsl, tr("GLSL")),
+ PAIR(ShaderBackend, Glasm, tr("GLASM (Assembly Shaders, NVIDIA Only)")),
+ PAIR(ShaderBackend, SpirV, tr("SPIR-V (Experimental, Mesa Only)")),
+ }});
translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
{
- PAIR(GpuAccuracy, Normal, "Normal"),
- PAIR(GpuAccuracy, High, "High"),
- PAIR(GpuAccuracy, Extreme, "Extreme"),
- }});
- translations->insert({Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
- {
- PAIR(CpuAccuracy, Auto, "Auto"),
- PAIR(CpuAccuracy, Accurate, "Accurate"),
- PAIR(CpuAccuracy, Unsafe, "Unsafe"),
- PAIR(CpuAccuracy, Paranoid, "Paranoid (disables most optimizations)"),
+ PAIR(GpuAccuracy, Normal, tr("Normal")),
+ PAIR(GpuAccuracy, High, tr("High")),
+ PAIR(GpuAccuracy, Extreme, tr("Extreme")),
}});
+ translations->insert(
+ {Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
+ {
+ PAIR(CpuAccuracy, Auto, tr("Auto")),
+ PAIR(CpuAccuracy, Accurate, tr("Accurate")),
+ PAIR(CpuAccuracy, Unsafe, tr("Unsafe")),
+ PAIR(CpuAccuracy, Paranoid, tr("Paranoid (disables most optimizations)")),
+ }});
translations->insert({Settings::EnumMetadata<Settings::FullscreenMode>::Index(),
{
- PAIR(FullscreenMode, Borderless, "Borderless Windowed"),
- PAIR(FullscreenMode, Exclusive, "Exclusive Fullscreen"),
+ PAIR(FullscreenMode, Borderless, tr("Borderless Windowed")),
+ PAIR(FullscreenMode, Exclusive, tr("Exclusive Fullscreen")),
}});
translations->insert({Settings::EnumMetadata<Settings::NvdecEmulation>::Index(),
{
- PAIR(NvdecEmulation, Off, "No Video Output"),
- PAIR(NvdecEmulation, Cpu, "CPU Video Decoding"),
- PAIR(NvdecEmulation, Gpu, "GPU Video Decoding (Default)"),
- }});
- translations->insert({Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
- {
- PAIR(ResolutionSetup, Res1_2X, "0.5X (360p/540p) [EXPERIMENTAL]"),
- PAIR(ResolutionSetup, Res3_4X, "0.75X (540p/810p) [EXPERIMENTAL]"),
- PAIR(ResolutionSetup, Res1X, "1X (720p/1080p)"),
- PAIR(ResolutionSetup, Res3_2X, "1.5X (1080p/1620p) [EXPERIMENTAL]"),
- PAIR(ResolutionSetup, Res2X, "2X (1440p/2160p)"),
- PAIR(ResolutionSetup, Res3X, "3X (2160p/3240p)"),
- PAIR(ResolutionSetup, Res4X, "4X (2880p/4320p)"),
- PAIR(ResolutionSetup, Res5X, "5X (3600p/5400p)"),
- PAIR(ResolutionSetup, Res6X, "6X (4320p/6480p)"),
- PAIR(ResolutionSetup, Res7X, "7X (5040p/7560p)"),
- PAIR(ResolutionSetup, Res8X, "8X (5760p/8640p)"),
+ PAIR(NvdecEmulation, Off, tr("No Video Output")),
+ PAIR(NvdecEmulation, Cpu, tr("CPU Video Decoding")),
+ PAIR(NvdecEmulation, Gpu, tr("GPU Video Decoding (Default)")),
}});
+ translations->insert(
+ {Settings::EnumMetadata<Settings::ResolutionSetup>::Index(),
+ {
+ PAIR(ResolutionSetup, Res1_2X, tr("0.5X (360p/540p) [EXPERIMENTAL]")),
+ PAIR(ResolutionSetup, Res3_4X, tr("0.75X (540p/810p) [EXPERIMENTAL]")),
+ PAIR(ResolutionSetup, Res1X, tr("1X (720p/1080p)")),
+ PAIR(ResolutionSetup, Res3_2X, tr("1.5X (1080p/1620p) [EXPERIMENTAL]")),
+ PAIR(ResolutionSetup, Res2X, tr("2X (1440p/2160p)")),
+ PAIR(ResolutionSetup, Res3X, tr("3X (2160p/3240p)")),
+ PAIR(ResolutionSetup, Res4X, tr("4X (2880p/4320p)")),
+ PAIR(ResolutionSetup, Res5X, tr("5X (3600p/5400p)")),
+ PAIR(ResolutionSetup, Res6X, tr("6X (4320p/6480p)")),
+ PAIR(ResolutionSetup, Res7X, tr("7X (5040p/7560p)")),
+ PAIR(ResolutionSetup, Res8X, tr("8X (5760p/8640p)")),
+ }});
translations->insert({Settings::EnumMetadata<Settings::ScalingFilter>::Index(),
{
- PAIR(ScalingFilter, NearestNeighbor, "Nearest Neighbor"),
- PAIR(ScalingFilter, Bilinear, "Bilinear"),
- PAIR(ScalingFilter, Bicubic, "Bicubic"),
- PAIR(ScalingFilter, Gaussian, "Gaussian"),
- PAIR(ScalingFilter, ScaleForce, "ScaleForce"),
- PAIR(ScalingFilter, Fsr, "AMD FidelityFX™️ Super Resolution"),
+ PAIR(ScalingFilter, NearestNeighbor, tr("Nearest Neighbor")),
+ PAIR(ScalingFilter, Bilinear, tr("Bilinear")),
+ PAIR(ScalingFilter, Bicubic, tr("Bicubic")),
+ PAIR(ScalingFilter, Gaussian, tr("Gaussian")),
+ PAIR(ScalingFilter, ScaleForce, tr("ScaleForce")),
+ PAIR(ScalingFilter, Fsr, tr("AMD FidelityFX™️ Super Resolution")),
}});
translations->insert({Settings::EnumMetadata<Settings::AntiAliasing>::Index(),
{
- PAIR(AntiAliasing, None, "None"),
- PAIR(AntiAliasing, Fxaa, "FXAA"),
- PAIR(AntiAliasing, Smaa, "SMAA"),
+ PAIR(AntiAliasing, None, tr("None")),
+ PAIR(AntiAliasing, Fxaa, tr("FXAA")),
+ PAIR(AntiAliasing, Smaa, tr("SMAA")),
}});
translations->insert({Settings::EnumMetadata<Settings::AspectRatio>::Index(),
{
- PAIR(AspectRatio, R16_9, "Default (16:9)"),
- PAIR(AspectRatio, R4_3, "Force 4:3"),
- PAIR(AspectRatio, R21_9, "Force 21:9"),
- PAIR(AspectRatio, R16_10, "Force 16:10"),
- PAIR(AspectRatio, Stretch, "Stretch to Window"),
+ PAIR(AspectRatio, R16_9, tr("Default (16:9)")),
+ PAIR(AspectRatio, R4_3, tr("Force 4:3")),
+ PAIR(AspectRatio, R21_9, tr("Force 21:9")),
+ PAIR(AspectRatio, R16_10, tr("Force 16:10")),
+ PAIR(AspectRatio, Stretch, tr("Stretch to Window")),
}});
translations->insert({Settings::EnumMetadata<Settings::AnisotropyMode>::Index(),
{
- PAIR(AnisotropyMode, Automatic, "Automatic"),
- PAIR(AnisotropyMode, Default, "Default"),
- PAIR(AnisotropyMode, X2, "2x"),
- PAIR(AnisotropyMode, X4, "4x"),
- PAIR(AnisotropyMode, X8, "8x"),
- PAIR(AnisotropyMode, X16, "16x"),
+ PAIR(AnisotropyMode, Automatic, tr("Automatic")),
+ PAIR(AnisotropyMode, Default, tr("Default")),
+ PAIR(AnisotropyMode, X2, tr("2x")),
+ PAIR(AnisotropyMode, X4, tr("4x")),
+ PAIR(AnisotropyMode, X8, tr("8x")),
+ PAIR(AnisotropyMode, X16, tr("16x")),
}});
translations->insert(
{Settings::EnumMetadata<Settings::Language>::Index(),
{
- PAIR(Language, Japanese, "Japanese (日本語)"),
- PAIR(Language, EnglishAmerican, "American English"),
- PAIR(Language, French, "French (français)"),
- PAIR(Language, German, "German (Deutsch)"),
- PAIR(Language, Italian, "Italian (italiano)"),
- PAIR(Language, Spanish, "Spanish (español)"),
- PAIR(Language, Chinese, "Chinese"),
- PAIR(Language, Korean, "Korean (한국어)"),
- PAIR(Language, Dutch, "Dutch (Nederlands)"),
- PAIR(Language, Portuguese, "Portuguese (português)"),
- PAIR(Language, Russian, "Russian (Русский)"),
- PAIR(Language, Taiwanese, "Taiwanese"),
- PAIR(Language, EnglishBritish, "British English"),
- PAIR(Language, FrenchCanadian, "Canadian French"),
- PAIR(Language, SpanishLatin, "Latin American Spanish"),
- PAIR(Language, ChineseSimplified, "Simplified Chinese"),
- PAIR(Language, ChineseTraditional, "Traditional Chinese (正體中文)"),
- PAIR(Language, PortugueseBrazilian, "Brazilian Portuguese (português do Brasil)"),
+ PAIR(Language, Japanese, tr("Japanese (日本語)")),
+ PAIR(Language, EnglishAmerican, tr("American English")),
+ PAIR(Language, French, tr("French (français)")),
+ PAIR(Language, German, tr("German (Deutsch)")),
+ PAIR(Language, Italian, tr("Italian (italiano)")),
+ PAIR(Language, Spanish, tr("Spanish (español)")),
+ PAIR(Language, Chinese, tr("Chinese")),
+ PAIR(Language, Korean, tr("Korean (한국어)")),
+ PAIR(Language, Dutch, tr("Dutch (Nederlands)")),
+ PAIR(Language, Portuguese, tr("Portuguese (português)")),
+ PAIR(Language, Russian, tr("Russian (Русский)")),
+ PAIR(Language, Taiwanese, tr("Taiwanese")),
+ PAIR(Language, EnglishBritish, tr("British English")),
+ PAIR(Language, FrenchCanadian, tr("Canadian French")),
+ PAIR(Language, SpanishLatin, tr("Latin American Spanish")),
+ PAIR(Language, ChineseSimplified, tr("Simplified Chinese")),
+ PAIR(Language, ChineseTraditional, tr("Traditional Chinese (正體中文)")),
+ PAIR(Language, PortugueseBrazilian, tr("Brazilian Portuguese (português do Brasil)")),
}});
translations->insert({Settings::EnumMetadata<Settings::Region>::Index(),
{
- PAIR(Region, Japan, "Japan"),
- PAIR(Region, Usa, "USA"),
- PAIR(Region, Europe, "Europe"),
- PAIR(Region, Australia, "Australia"),
- PAIR(Region, China, "China"),
- PAIR(Region, Korea, "Korea"),
- PAIR(Region, Taiwan, "Taiwan"),
+ PAIR(Region, Japan, tr("Japan")),
+ PAIR(Region, Usa, tr("USA")),
+ PAIR(Region, Europe, tr("Europe")),
+ PAIR(Region, Australia, tr("Australia")),
+ PAIR(Region, China, tr("China")),
+ PAIR(Region, Korea, tr("Korea")),
+ PAIR(Region, Taiwan, tr("Taiwan")),
}});
translations->insert(
{Settings::EnumMetadata<Settings::TimeZone>::Index(),
@@ -323,72 +340,74 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QWidget* parent) {
{static_cast<u32>(Settings::TimeZone::Default),
tr("Default (%1)", "Default time zone")
.arg(QString::fromStdString(Common::TimeZone::GetDefaultTimeZone()))},
- PAIR(TimeZone, Cet, "CET"),
- PAIR(TimeZone, Cst6Cdt, "CST6CDT"),
- PAIR(TimeZone, Cuba, "Cuba"),
- PAIR(TimeZone, Eet, "EET"),
- PAIR(TimeZone, Egypt, "Egypt"),
- PAIR(TimeZone, Eire, "Eire"),
- PAIR(TimeZone, Est, "EST"),
- PAIR(TimeZone, Est5Edt, "EST5EDT"),
- PAIR(TimeZone, Gb, "GB"),
- PAIR(TimeZone, GbEire, "GB-Eire"),
- PAIR(TimeZone, Gmt, "GMT"),
- PAIR(TimeZone, GmtPlusZero, "GMT+0"),
- PAIR(TimeZone, GmtMinusZero, "GMT-0"),
- PAIR(TimeZone, GmtZero, "GMT0"),
- PAIR(TimeZone, Greenwich, "Greenwich"),
- PAIR(TimeZone, Hongkong, "Hongkong"),
- PAIR(TimeZone, Hst, "HST"),
- PAIR(TimeZone, Iceland, "Iceland"),
- PAIR(TimeZone, Iran, "Iran"),
- PAIR(TimeZone, Israel, "Israel"),
- PAIR(TimeZone, Jamaica, "Jamaica"),
- PAIR(TimeZone, Japan, "Japan"),
- PAIR(TimeZone, Kwajalein, "Kwajalein"),
- PAIR(TimeZone, Libya, "Libya"),
- PAIR(TimeZone, Met, "MET"),
- PAIR(TimeZone, Mst, "MST"),
- PAIR(TimeZone, Mst7Mdt, "MST7MDT"),
- PAIR(TimeZone, Navajo, "Navajo"),
- PAIR(TimeZone, Nz, "NZ"),
- PAIR(TimeZone, NzChat, "NZ-CHAT"),
- PAIR(TimeZone, Poland, "Poland"),
- PAIR(TimeZone, Portugal, "Portugal"),
- PAIR(TimeZone, Prc, "PRC"),
- PAIR(TimeZone, Pst8Pdt, "PST8PDT"),
- PAIR(TimeZone, Roc, "ROC"),
- PAIR(TimeZone, Rok, "ROK"),
- PAIR(TimeZone, Singapore, "Singapore"),
- PAIR(TimeZone, Turkey, "Turkey"),
- PAIR(TimeZone, Uct, "UCT"),
- PAIR(TimeZone, Universal, "Universal"),
- PAIR(TimeZone, Utc, "UTC"),
- PAIR(TimeZone, WSu, "W-SU"),
- PAIR(TimeZone, Wet, "WET"),
- PAIR(TimeZone, Zulu, "Zulu"),
+ PAIR(TimeZone, Cet, tr("CET")),
+ PAIR(TimeZone, Cst6Cdt, tr("CST6CDT")),
+ PAIR(TimeZone, Cuba, tr("Cuba")),
+ PAIR(TimeZone, Eet, tr("EET")),
+ PAIR(TimeZone, Egypt, tr("Egypt")),
+ PAIR(TimeZone, Eire, tr("Eire")),
+ PAIR(TimeZone, Est, tr("EST")),
+ PAIR(TimeZone, Est5Edt, tr("EST5EDT")),
+ PAIR(TimeZone, Gb, tr("GB")),
+ PAIR(TimeZone, GbEire, tr("GB-Eire")),
+ PAIR(TimeZone, Gmt, tr("GMT")),
+ PAIR(TimeZone, GmtPlusZero, tr("GMT+0")),
+ PAIR(TimeZone, GmtMinusZero, tr("GMT-0")),
+ PAIR(TimeZone, GmtZero, tr("GMT0")),
+ PAIR(TimeZone, Greenwich, tr("Greenwich")),
+ PAIR(TimeZone, Hongkong, tr("Hongkong")),
+ PAIR(TimeZone, Hst, tr("HST")),
+ PAIR(TimeZone, Iceland, tr("Iceland")),
+ PAIR(TimeZone, Iran, tr("Iran")),
+ PAIR(TimeZone, Israel, tr("Israel")),
+ PAIR(TimeZone, Jamaica, tr("Jamaica")),
+ PAIR(TimeZone, Japan, tr("Japan")),
+ PAIR(TimeZone, Kwajalein, tr("Kwajalein")),
+ PAIR(TimeZone, Libya, tr("Libya")),
+ PAIR(TimeZone, Met, tr("MET")),
+ PAIR(TimeZone, Mst, tr("MST")),
+ PAIR(TimeZone, Mst7Mdt, tr("MST7MDT")),
+ PAIR(TimeZone, Navajo, tr("Navajo")),
+ PAIR(TimeZone, Nz, tr("NZ")),
+ PAIR(TimeZone, NzChat, tr("NZ-CHAT")),
+ PAIR(TimeZone, Poland, tr("Poland")),
+ PAIR(TimeZone, Portugal, tr("Portugal")),
+ PAIR(TimeZone, Prc, tr("PRC")),
+ PAIR(TimeZone, Pst8Pdt, tr("PST8PDT")),
+ PAIR(TimeZone, Roc, tr("ROC")),
+ PAIR(TimeZone, Rok, tr("ROK")),
+ PAIR(TimeZone, Singapore, tr("Singapore")),
+ PAIR(TimeZone, Turkey, tr("Turkey")),
+ PAIR(TimeZone, Uct, tr("UCT")),
+ PAIR(TimeZone, Universal, tr("Universal")),
+ PAIR(TimeZone, Utc, tr("UTC")),
+ PAIR(TimeZone, WSu, tr("W-SU")),
+ PAIR(TimeZone, Wet, tr("WET")),
+ PAIR(TimeZone, Zulu, tr("Zulu")),
}});
translations->insert({Settings::EnumMetadata<Settings::AudioMode>::Index(),
{
- PAIR(AudioMode, Mono, "Mono"),
- PAIR(AudioMode, Stereo, "Stereo"),
- PAIR(AudioMode, Surround, "Surround"),
+ PAIR(AudioMode, Mono, tr("Mono")),
+ PAIR(AudioMode, Stereo, tr("Stereo")),
+ PAIR(AudioMode, Surround, tr("Surround")),
}});
translations->insert({Settings::EnumMetadata<Settings::MemoryLayout>::Index(),
{
- PAIR(MemoryLayout, Memory_4Gb, "4GB DRAM (Default)"),
- PAIR(MemoryLayout, Memory_6Gb, "6GB DRAM (Unsafe)"),
- PAIR(MemoryLayout, Memory_8Gb, "8GB DRAM (Unsafe)"),
+ PAIR(MemoryLayout, Memory_4Gb, tr("4GB DRAM (Default)")),
+ PAIR(MemoryLayout, Memory_6Gb, tr("6GB DRAM (Unsafe)")),
+ PAIR(MemoryLayout, Memory_8Gb, tr("8GB DRAM (Unsafe)")),
+ }});
+ translations->insert({Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
+ {
+ PAIR(ConsoleMode, Docked, tr("Docked")),
+ PAIR(ConsoleMode, Handheld, tr("Handheld")),
}});
- translations->insert(
- {Settings::EnumMetadata<Settings::ConsoleMode>::Index(),
- {PAIR(ConsoleMode, Docked, "Docked"), PAIR(ConsoleMode, Handheld, "Handheld")}});
translations->insert(
{Settings::EnumMetadata<Settings::ConfirmStop>::Index(),
{
- PAIR(ConfirmStop, Ask_Always, "Always ask (Default)"),
- PAIR(ConfirmStop, Ask_Based_On_Game, "Only if game specifies not to stop"),
- PAIR(ConfirmStop, Ask_Never, "Never ask"),
+ PAIR(ConfirmStop, Ask_Always, tr("Always ask (Default)")),
+ PAIR(ConfirmStop, Ask_Based_On_Game, tr("Only if game specifies not to stop")),
+ PAIR(ConfirmStop, Ask_Never, tr("Never ask")),
}});
#undef PAIR
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
QAction* verify_integrity = context_menu.addAction(tr("Verify Integrity"));
QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
+// TODO: Implement shortcut creation for macOS
+#if !defined(__APPLE__)
QMenu* shortcut_menu = context_menu.addMenu(tr("Create Shortcut"));
QAction* create_desktop_shortcut = shortcut_menu->addAction(tr("Add to Desktop"));
-#ifndef WIN32
QAction* create_applications_menu_shortcut =
shortcut_menu->addAction(tr("Add to Applications Menu"));
#endif
@@ -647,10 +648,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() {
emit NavigateToGamedbEntryRequested(program_id, compatibility_list);
});
+// TODO: Implement shortcut creation for macOS
+#if !defined(__APPLE__)
connect(create_desktop_shortcut, &QAction::triggered, [this, program_id, path]() {
emit CreateShortcut(program_id, path, GameListShortcutTarget::Desktop);
});
-#ifndef WIN32
connect(create_applications_menu_shortcut, &QAction::triggered, [this, program_id, path]() {
emit CreateShortcut(program_id, path, GameListShortcutTarget::Applications);
});
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index f077d7f9c..f22db233b 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -10,6 +10,7 @@
#include <thread>
#include "core/loader/nca.h"
#include "core/tools/renderdoc.h"
+
#ifdef __APPLE__
#include <unistd.h> // for chdir
#endif
@@ -1574,6 +1575,7 @@ void GMainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Load_Cabinet_Formatter,
[this]() { OnCabinet(Service::NFP::CabinetMode::StartFormatter); });
connect_menu(ui->action_Load_Mii_Edit, &GMainWindow::OnMiiEdit);
+ connect_menu(ui->action_Open_Controller_Menu, &GMainWindow::OnOpenControllerMenu);
connect_menu(ui->action_Capture_Screenshot, &GMainWindow::OnCaptureScreenshot);
// TAS
@@ -1601,14 +1603,13 @@ void GMainWindow::UpdateMenuState() {
ui->action_Pause,
};
- const std::array applet_actions{
- ui->action_Load_Album,
- ui->action_Load_Cabinet_Nickname_Owner,
- ui->action_Load_Cabinet_Eraser,
- ui->action_Load_Cabinet_Restorer,
- ui->action_Load_Cabinet_Formatter,
- ui->action_Load_Mii_Edit,
- };
+ const std::array applet_actions{ui->action_Load_Album,
+ ui->action_Load_Cabinet_Nickname_Owner,
+ ui->action_Load_Cabinet_Eraser,
+ ui->action_Load_Cabinet_Restorer,
+ ui->action_Load_Cabinet_Formatter,
+ ui->action_Load_Mii_Edit,
+ ui->action_Open_Controller_Menu};
for (QAction* action : running_actions) {
action->setEnabled(emulation_running);
@@ -2847,170 +2848,259 @@ void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id,
QDesktopServices::openUrl(QUrl(QStringLiteral("https://yuzu-emu.org/game/") + directory));
}
-void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
- GameListShortcutTarget target) {
- // Get path to yuzu executable
- const QStringList args = QApplication::arguments();
- std::filesystem::path yuzu_command = args[0].toStdString();
-
- // If relative path, make it an absolute path
- if (yuzu_command.c_str()[0] == '.') {
- yuzu_command = Common::FS::GetCurrentDir() / yuzu_command;
+bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
+ const std::string& comment,
+ const std::filesystem::path& icon_path,
+ const std::filesystem::path& command,
+ const std::string& arguments, const std::string& categories,
+ const std::string& keywords, const std::string& name) try {
+#if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD
+ std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop");
+ std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc);
+ if (!shortcut_stream.is_open()) {
+ LOG_ERROR(Frontend, "Failed to create shortcut");
+ return false;
}
-
-#if defined(__linux__)
- // Warn once if we are making a shortcut to a volatile AppImage
- const std::string appimage_ending =
- std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage");
- if (yuzu_command.string().ends_with(appimage_ending) &&
- !UISettings::values.shortcut_already_warned) {
- if (QMessageBox::warning(this, tr("Create Shortcut"),
- tr("This will create a shortcut to the current AppImage. This may "
- "not work well if you update. Continue?"),
- QMessageBox::StandardButton::Ok |
- QMessageBox::StandardButton::Cancel) ==
- QMessageBox::StandardButton::Cancel) {
- return;
+ // TODO: Migrate fmt::print to std::print in futures STD C++ 23.
+ fmt::print(shortcut_stream, "[Desktop Entry]\n");
+ fmt::print(shortcut_stream, "Type=Application\n");
+ fmt::print(shortcut_stream, "Version=1.0\n");
+ fmt::print(shortcut_stream, "Name={}\n", name);
+ if (!comment.empty()) {
+ fmt::print(shortcut_stream, "Comment={}\n", comment);
+ }
+ if (std::filesystem::is_regular_file(icon_path)) {
+ fmt::print(shortcut_stream, "Icon={}\n", icon_path.string());
+ }
+ fmt::print(shortcut_stream, "TryExec={}\n", command.string());
+ fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments);
+ if (!categories.empty()) {
+ fmt::print(shortcut_stream, "Categories={}\n", categories);
+ }
+ if (!keywords.empty()) {
+ fmt::print(shortcut_stream, "Keywords={}\n", keywords);
+ }
+ return true;
+#elif defined(_WIN32) // Windows
+ HRESULT hr = CoInitialize(nullptr);
+ if (FAILED(hr)) {
+ LOG_ERROR(Frontend, "CoInitialize failed");
+ return false;
+ }
+ SCOPE_EXIT({ CoUninitialize(); });
+ IShellLinkW* ps1 = nullptr;
+ IPersistFile* persist_file = nullptr;
+ SCOPE_EXIT({
+ if (persist_file != nullptr) {
+ persist_file->Release();
}
- UISettings::values.shortcut_already_warned = true;
+ if (ps1 != nullptr) {
+ ps1->Release();
+ }
+ });
+ HRESULT hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
+ reinterpret_cast<void**>(&ps1));
+ if (FAILED(hres)) {
+ LOG_ERROR(Frontend, "Failed to create IShellLinkW instance");
+ return false;
}
-#endif // __linux__
-
- std::filesystem::path target_directory{};
-
- switch (target) {
- case GameListShortcutTarget::Desktop: {
- const QString desktop_path =
- QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
- target_directory = desktop_path.toUtf8().toStdString();
- break;
+ hres = ps1->SetPath(command.c_str());
+ if (FAILED(hres)) {
+ LOG_ERROR(Frontend, "Failed to set path");
+ return false;
}
- case GameListShortcutTarget::Applications: {
- const QString applications_path =
- QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
- if (applications_path.isEmpty()) {
- const char* home = std::getenv("HOME");
- if (home != nullptr) {
- target_directory = std::filesystem::path(home) / ".local/share/applications";
- }
- } else {
- target_directory = applications_path.toUtf8().toStdString();
+ if (!arguments.empty()) {
+ hres = ps1->SetArguments(Common::UTF8ToUTF16W(arguments).data());
+ if (FAILED(hres)) {
+ LOG_ERROR(Frontend, "Failed to set arguments");
+ return false;
}
- break;
}
- default:
- return;
+ if (!comment.empty()) {
+ hres = ps1->SetDescription(Common::UTF8ToUTF16W(comment).data());
+ if (FAILED(hres)) {
+ LOG_ERROR(Frontend, "Failed to set description");
+ return false;
+ }
}
-
- const QDir dir(QString::fromStdString(target_directory.generic_string()));
- if (!dir.exists()) {
- QMessageBox::critical(this, tr("Create Shortcut"),
- tr("Cannot create shortcut. Path \"%1\" does not exist.")
- .arg(QString::fromStdString(target_directory.generic_string())),
- QMessageBox::StandardButton::Ok);
- return;
+ if (std::filesystem::is_regular_file(icon_path)) {
+ hres = ps1->SetIconLocation(icon_path.c_str(), 0);
+ if (FAILED(hres)) {
+ LOG_ERROR(Frontend, "Failed to set icon location");
+ return false;
+ }
}
+ hres = ps1->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&persist_file));
+ if (FAILED(hres)) {
+ LOG_ERROR(Frontend, "Failed to get IPersistFile interface");
+ return false;
+ }
+ hres = persist_file->Save(std::filesystem::path{shortcut_path / (name + ".lnk")}.c_str(), TRUE);
+ if (FAILED(hres)) {
+ LOG_ERROR(Frontend, "Failed to save shortcut");
+ return false;
+ }
+ return true;
+#else // Unsupported platform
+ return false;
+#endif
+} catch (const std::exception& e) {
+ LOG_ERROR(Frontend, "Failed to create shortcut: {}", e.what());
+ return false;
+}
+// Messages in pre-defined message boxes for less code spaghetti
+bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title) {
+ int result = 0;
+ QMessageBox::StandardButtons buttons;
+ switch (imsg) {
+ case GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES:
+ buttons = QMessageBox::Yes | QMessageBox::No;
+ result =
+ QMessageBox::information(parent, tr("Create Shortcut"),
+ tr("Do you want to launch the game in fullscreen?"), buttons);
+ return result == QMessageBox::Yes;
+ case GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS:
+ QMessageBox::information(parent, tr("Create Shortcut"),
+ tr("Successfully created a shortcut to %1").arg(game_title));
+ return false;
+ case GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING:
+ buttons = QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel;
+ result =
+ QMessageBox::warning(this, tr("Create Shortcut"),
+ tr("This will create a shortcut to the current AppImage. This may "
+ "not work well if you update. Continue?"),
+ buttons);
+ return result == QMessageBox::Ok;
+ default:
+ buttons = QMessageBox::Ok;
+ QMessageBox::critical(parent, tr("Create Shortcut"),
+ tr("Failed to create a shortcut to %1").arg(game_title), buttons);
+ return false;
+ }
+}
- const std::string game_file_name = std::filesystem::path(game_path).filename().string();
- // Determine full paths for icon and shortcut
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
- const char* home = std::getenv("HOME");
- const std::filesystem::path home_path = (home == nullptr ? "~" : home);
- const char* xdg_data_home = std::getenv("XDG_DATA_HOME");
-
- std::filesystem::path system_icons_path =
- (xdg_data_home == nullptr ? home_path / ".local/share/"
- : std::filesystem::path(xdg_data_home)) /
- "icons/hicolor/256x256";
- if (!Common::FS::CreateDirs(system_icons_path)) {
+bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
+ std::filesystem::path& out_icon_path) {
+ // Get path to Yuzu icons directory & icon extension
+ std::string ico_extension = "png";
+#if defined(_WIN32)
+ out_icon_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::IconsDir);
+ ico_extension = "ico";
+#elif defined(__linux__) || defined(__FreeBSD__)
+ out_icon_path = Common::FS::GetDataDirectory("XDG_DATA_HOME") / "icons/hicolor/256x256";
+#endif
+ // Create icons directory if it doesn't exist
+ if (!Common::FS::CreateDirs(out_icon_path)) {
QMessageBox::critical(
this, tr("Create Icon"),
tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.")
- .arg(QString::fromStdString(system_icons_path)),
+ .arg(QString::fromStdString(out_icon_path.string())),
QMessageBox::StandardButton::Ok);
- return;
+ out_icon_path.clear();
+ return false;
}
- std::filesystem::path icon_path =
- system_icons_path / (program_id == 0 ? fmt::format("yuzu-{}.png", game_file_name)
- : fmt::format("yuzu-{:016X}.png", program_id));
- const std::filesystem::path shortcut_path =
- target_directory / (program_id == 0 ? fmt::format("yuzu-{}.desktop", game_file_name)
- : fmt::format("yuzu-{:016X}.desktop", program_id));
-#elif defined(WIN32)
- std::filesystem::path icons_path =
- Common::FS::GetYuzuPathString(Common::FS::YuzuPath::IconsDir);
- std::filesystem::path icon_path =
- icons_path / ((program_id == 0 ? fmt::format("yuzu-{}.ico", game_file_name)
- : fmt::format("yuzu-{:016X}.ico", program_id)));
-#else
- std::string icon_extension;
-#endif
-
- // Get title from game file
- const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
- system->GetContentProvider()};
- const auto control = pm.GetControlMetadata();
- const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read));
- std::string title{fmt::format("{:016X}", program_id)};
-
- if (control.first != nullptr) {
- title = control.first->GetApplicationName();
- } else {
- loader->ReadTitle(title);
- }
+ // Create icon file path
+ out_icon_path /= (program_id == 0 ? fmt::format("yuzu-{}.{}", game_file_name, ico_extension)
+ : fmt::format("yuzu-{:016X}.{}", program_id, ico_extension));
+ return true;
+}
- // Get icon from game file
- std::vector<u8> icon_image_file{};
- if (control.second != nullptr) {
- icon_image_file = control.second->ReadAllBytes();
- } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
- LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
+void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
+ GameListShortcutTarget target) {
+ std::string game_title;
+ QString qt_game_title;
+ std::filesystem::path out_icon_path;
+ // Get path to yuzu executable
+ const QStringList args = QApplication::arguments();
+ std::filesystem::path yuzu_command = args[0].toStdString();
+ // If relative path, make it an absolute path
+ if (yuzu_command.c_str()[0] == '.') {
+ yuzu_command = Common::FS::GetCurrentDir() / yuzu_command;
}
-
- QImage icon_data =
- QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
- // Convert and write the icon as a PNG
- if (!icon_data.save(QString::fromStdString(icon_path.string()))) {
- LOG_ERROR(Frontend, "Could not write icon as PNG to file");
+ // Shortcut path
+ std::filesystem::path shortcut_path{};
+ if (target == GameListShortcutTarget::Desktop) {
+ shortcut_path =
+ QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString();
+ } else if (target == GameListShortcutTarget::Applications) {
+ shortcut_path =
+ QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
+ }
+ // Icon path and title
+ if (std::filesystem::exists(shortcut_path)) {
+ // Get title from game file
+ const FileSys::PatchManager pm{program_id, system->GetFileSystemController(),
+ system->GetContentProvider()};
+ const auto control = pm.GetControlMetadata();
+ const auto loader =
+ Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read));
+ game_title = fmt::format("{:016X}", program_id);
+ if (control.first != nullptr) {
+ game_title = control.first->GetApplicationName();
+ } else {
+ loader->ReadTitle(game_title);
+ }
+ // Delete illegal characters from title
+ const std::string illegal_chars = "<>:\"/\\|?*.";
+ for (auto it = game_title.rbegin(); it != game_title.rend(); ++it) {
+ if (illegal_chars.find(*it) != std::string::npos) {
+ game_title.erase(it.base() - 1);
+ }
+ }
+ qt_game_title = QString::fromStdString(game_title);
+ // Get icon from game file
+ std::vector<u8> icon_image_file{};
+ if (control.second != nullptr) {
+ icon_image_file = control.second->ReadAllBytes();
+ } else if (loader->ReadIcon(icon_image_file) != Loader::ResultStatus::Success) {
+ LOG_WARNING(Frontend, "Could not read icon from {:s}", game_path);
+ }
+ QImage icon_data =
+ QImage::fromData(icon_image_file.data(), static_cast<int>(icon_image_file.size()));
+ if (GMainWindow::MakeShortcutIcoPath(program_id, game_title, out_icon_path)) {
+ if (!SaveIconToFile(out_icon_path, icon_data)) {
+ LOG_ERROR(Frontend, "Could not write icon to file");
+ }
+ }
} else {
- LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string());
- }
-#elif defined(WIN32)
- if (!SaveIconToFile(icon_path.string(), icon_data)) {
- LOG_ERROR(Frontend, "Could not write icon to file");
+ GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
+ qt_game_title);
+ LOG_ERROR(Frontend, "Invalid shortcut target");
return;
}
+#if defined(__linux__)
+ // Special case for AppImages
+ // Warn once if we are making a shortcut to a volatile AppImage
+ const std::string appimage_ending =
+ std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage");
+ if (yuzu_command.string().ends_with(appimage_ending) &&
+ !UISettings::values.shortcut_already_warned) {
+ if (GMainWindow::CreateShortcutMessagesGUI(
+ this, GMainWindow::CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, qt_game_title)) {
+ return;
+ }
+ UISettings::values.shortcut_already_warned = true;
+ }
#endif // __linux__
-
-#ifdef _WIN32
- // Replace characters that are illegal in Windows filenames by a dash
- const std::string illegal_chars = "<>:\"/\\|?*";
- for (char c : illegal_chars) {
- std::replace(title.begin(), title.end(), c, '_');
+ // Create shortcut
+ std::string arguments = fmt::format("-g \"{:s}\"", game_path);
+ if (GMainWindow::CreateShortcutMessagesGUI(
+ this, GMainWindow::CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, qt_game_title)) {
+ arguments = "-f " + arguments;
}
- const std::filesystem::path shortcut_path = target_directory / (title + ".lnk").c_str();
-#endif
-
- const std::string comment =
- tr("Start %1 with the yuzu Emulator").arg(QString::fromStdString(title)).toStdString();
- const std::string arguments = fmt::format("-g \"{:s}\"", game_path);
+ const std::string comment = fmt::format("Start {:s} with the yuzu Emulator", game_title);
const std::string categories = "Game;Emulator;Qt;";
const std::string keywords = "Switch;Nintendo;";
- if (!CreateShortcut(shortcut_path.string(), title, comment, icon_path.string(),
- yuzu_command.string(), arguments, categories, keywords)) {
- QMessageBox::critical(this, tr("Create Shortcut"),
- tr("Failed to create a shortcut at %1")
- .arg(QString::fromStdString(shortcut_path.string())));
+ if (GMainWindow::CreateShortcutLink(shortcut_path, comment, out_icon_path, yuzu_command,
+ arguments, categories, keywords, game_title)) {
+ GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_SUCCESS,
+ qt_game_title);
return;
}
-
- LOG_INFO(Frontend, "Wrote a shortcut to {}", shortcut_path.string());
- QMessageBox::information(
- this, tr("Create Shortcut"),
- tr("Successfully created a shortcut to %1").arg(QString::fromStdString(title)));
+ GMainWindow::CreateShortcutMessagesGUI(this, GMainWindow::CREATE_SHORTCUT_MSGBOX_ERROR,
+ qt_game_title);
}
void GMainWindow::OnGameListOpenDirectory(const QString& directory) {
@@ -4005,66 +4095,6 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file
}
}
-bool GMainWindow::CreateShortcut(const std::string& shortcut_path, const std::string& title,
- const std::string& comment, const std::string& icon_path,
- const std::string& command, const std::string& arguments,
- const std::string& categories, const std::string& keywords) {
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
- // This desktop file template was writing referencing
- // https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html
- std::string shortcut_contents{};
- shortcut_contents.append("[Desktop Entry]\n");
- shortcut_contents.append("Type=Application\n");
- shortcut_contents.append("Version=1.0\n");
- shortcut_contents.append(fmt::format("Name={:s}\n", title));
- shortcut_contents.append(fmt::format("Comment={:s}\n", comment));
- shortcut_contents.append(fmt::format("Icon={:s}\n", icon_path));
- shortcut_contents.append(fmt::format("TryExec={:s}\n", command));
- shortcut_contents.append(fmt::format("Exec={:s} {:s}\n", command, arguments));
- shortcut_contents.append(fmt::format("Categories={:s}\n", categories));
- shortcut_contents.append(fmt::format("Keywords={:s}\n", keywords));
-
- std::ofstream shortcut_stream(shortcut_path);
- if (!shortcut_stream.is_open()) {
- LOG_WARNING(Common, "Failed to create file {:s}", shortcut_path);
- return false;
- }
- shortcut_stream << shortcut_contents;
- shortcut_stream.close();
-
- return true;
-#elif defined(WIN32)
- IShellLinkW* shell_link;
- auto hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
- (void**)&shell_link);
- if (FAILED(hres)) {
- return false;
- }
- shell_link->SetPath(
- Common::UTF8ToUTF16W(command).data()); // Path to the object we are referring to
- shell_link->SetArguments(Common::UTF8ToUTF16W(arguments).data());
- shell_link->SetDescription(Common::UTF8ToUTF16W(comment).data());
- shell_link->SetIconLocation(Common::UTF8ToUTF16W(icon_path).data(), 0);
-
- IPersistFile* persist_file;
- hres = shell_link->QueryInterface(IID_IPersistFile, (void**)&persist_file);
- if (FAILED(hres)) {
- return false;
- }
-
- hres = persist_file->Save(Common::UTF8ToUTF16W(shortcut_path).data(), TRUE);
- if (FAILED(hres)) {
- return false;
- }
-
- persist_file->Release();
- shell_link->Release();
-
- return true;
-#endif
- return false;
-}
-
void GMainWindow::OnLoadAmiibo() {
if (emu_thread == nullptr || !emu_thread->IsRunning()) {
return;
@@ -4103,7 +4133,6 @@ void GMainWindow::OnLoadAmiibo() {
bool GMainWindow::question(QWidget* parent, const QString& title, const QString& text,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton) {
-
QMessageBox* box_dialog = new QMessageBox(parent);
box_dialog->setWindowTitle(title);
box_dialog->setText(text);
@@ -4346,6 +4375,31 @@ void GMainWindow::OnMiiEdit() {
BootGame(filename, MiiEditId);
}
+void GMainWindow::OnOpenControllerMenu() {
+ constexpr u64 ControllerAppletId =
+ static_cast<u64>(Service::AM::Applets::AppletProgramId::Controller);
+ auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
+ if (!bis_system) {
+ QMessageBox::warning(this, tr("No firmware available"),
+ tr("Please install the firmware to use the Controller Menu."));
+ return;
+ }
+
+ auto controller_applet_nca =
+ bis_system->GetEntry(ControllerAppletId, FileSys::ContentRecordType::Program);
+ if (!controller_applet_nca) {
+ QMessageBox::warning(this, tr("Controller Applet"),
+ tr("Controller Menu is not available. Please reinstall firmware."));
+ return;
+ }
+
+ system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller);
+
+ const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath()));
+ UISettings::values.roms_path = QFileInfo(filename).path();
+ BootGame(filename, ControllerAppletId);
+}
+
void GMainWindow::OnCaptureScreenshot() {
if (emu_thread == nullptr || !emu_thread->IsRunning()) {
return;
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index f9c6efe4f..49ee1e1d2 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -6,6 +6,7 @@
#include <memory>
#include <optional>
+#include <filesystem>
#include <QMainWindow>
#include <QMessageBox>
#include <QPushButton>
@@ -174,6 +175,13 @@ class GMainWindow : public QMainWindow {
UI_EMU_STOPPING,
};
+ enum {
+ CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES,
+ CREATE_SHORTCUT_MSGBOX_SUCCESS,
+ CREATE_SHORTCUT_MSGBOX_ERROR,
+ CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING,
+ };
+
public:
void filterBarSetChecked(bool state);
void UpdateUITheme();
@@ -402,6 +410,7 @@ private slots:
void OnAlbum();
void OnCabinet(Service::NFP::CabinetMode mode);
void OnMiiEdit();
+ void OnOpenControllerMenu();
void OnCaptureScreenshot();
void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
void OnLanguageChanged(const QString& locale);
@@ -456,11 +465,14 @@ private:
bool ConfirmShutdownGame();
QString GetTasStateDescription() const;
- bool CreateShortcut(const std::string& shortcut_path, const std::string& title,
- const std::string& comment, const std::string& icon_path,
- const std::string& command, const std::string& arguments,
- const std::string& categories, const std::string& keywords);
-
+ bool CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title);
+ bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
+ std::filesystem::path& out_icon_path);
+ bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment,
+ const std::filesystem::path& icon_path,
+ const std::filesystem::path& command, const std::string& arguments,
+ const std::string& categories, const std::string& keywords,
+ const std::string& name);
/**
* Mimic the behavior of QMessageBox::question but link controller navigation to the dialog
* The only difference is that it returns a boolean.
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 88684ffb5..e53f9951e 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -25,7 +25,7 @@
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
- <property name="margin">
+ <property name="margin" stdset="0">
<number>0</number>
</property>
</layout>
@@ -36,7 +36,7 @@
<x>0</x>
<y>0</y>
<width>1280</width>
- <height>26</height>
+ <height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@@ -162,6 +162,7 @@
<addaction name="menu_cabinet_applet"/>
<addaction name="action_Load_Album"/>
<addaction name="action_Load_Mii_Edit"/>
+ <addaction name="action_Open_Controller_Menu"/>
<addaction name="separator"/>
<addaction name="action_Capture_Screenshot"/>
<addaction name="menuTAS"/>
@@ -382,9 +383,9 @@
</property>
</action>
<action name="action_Load_Album">
- <property name="text">
- <string>Open &amp;Album</string>
- </property>
+ <property name="text">
+ <string>Open &amp;Album</string>
+ </property>
</action>
<action name="action_Load_Cabinet_Nickname_Owner">
<property name="text">
@@ -407,9 +408,9 @@
</property>
</action>
<action name="action_Load_Mii_Edit">
- <property name="text">
- <string>Open &amp;Mii Editor</string>
- </property>
+ <property name="text">
+ <string>Open &amp;Mii Editor</string>
+ </property>
</action>
<action name="action_Configure_Tas">
<property name="text">
@@ -454,6 +455,11 @@
<string>R&amp;ecord</string>
</property>
</action>
+ <action name="action_Open_Controller_Menu">
+ <property name="text">
+ <string>Open &amp;Controller Menu</string>
+ </property>
+ </action>
</widget>
<resources>
<include location="yuzu.qrc"/>
diff --git a/src/yuzu/util/util.cpp b/src/yuzu/util/util.cpp
index f2854c8ec..e22cf84bf 100644
--- a/src/yuzu/util/util.cpp
+++ b/src/yuzu/util/util.cpp
@@ -4,7 +4,10 @@
#include <array>
#include <cmath>
#include <QPainter>
+
+#include "common/logging/log.h"
#include "yuzu/util/util.h"
+
#ifdef _WIN32
#include <windows.h>
#include "common/fs/file.h"
@@ -42,7 +45,7 @@ QPixmap CreateCirclePixmapFromColor(const QColor& color) {
return circle_pixmap;
}
-bool SaveIconToFile(const std::string_view path, const QImage& image) {
+bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image) {
#if defined(WIN32)
#pragma pack(push, 2)
struct IconDir {
@@ -73,7 +76,7 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) {
.id_count = static_cast<WORD>(scale_sizes.size()),
};
- Common::FS::IOFile icon_file(path, Common::FS::FileAccessMode::Write,
+ Common::FS::IOFile icon_file(icon_path.string(), Common::FS::FileAccessMode::Write,
Common::FS::FileType::BinaryFile);
if (!icon_file.IsOpen()) {
return false;
@@ -135,6 +138,14 @@ bool SaveIconToFile(const std::string_view path, const QImage& image) {
icon_file.Close();
return true;
+#elif defined(__linux__) || defined(__FreeBSD__)
+ // Convert and write the icon as a PNG
+ if (!image.save(QString::fromStdString(icon_path.string()))) {
+ LOG_ERROR(Frontend, "Could not write icon as PNG to file");
+ } else {
+ LOG_INFO(Frontend, "Wrote an icon to {}", icon_path.string());
+ }
+ return true;
#else
return false;
#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 @@
#pragma once
+#include <filesystem>
#include <QFont>
#include <QString>
@@ -25,4 +26,4 @@
* @param image The image to save
* @return bool If the operation succeeded
*/
-[[nodiscard]] bool SaveIconToFile(const std::string_view path, const QImage& image);
+[[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image);